HR's Blog

Swimming 🏊 in the sea🌊of code!

0%

Weak 1.原理解析

.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@interface HRObject : NSObject
@property (nonatomic, strong) NSObject *objectA;
@property (nonatomic, strong) NSObject *objectB;
@end

@implementation HRObject
- (void)weakTest {
self.objectA = [NSObject new];
self.objectB = [NSObject new];

__weak NSObject *weakObject = self.objectA;
weakObject = self.objectB;

}
@end

int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
[[HRObject new] weakTest];
}
return 0;
}
1
clang -rewrite-objc -fobjc-arc -stdlib=libc++ -mmacosx-version-min=10.7 -fobjc-runtime=macosx-10.7 -Wno-deprecated-declarations main.m
1
2
3
4
5
6
7
8
static void _I_HRObject_weakTest(HRObject * self, SEL _cmd) {
((void (*)(id, SEL, NSObject *))(void *)objc_msgSend)((id)self, sel_registerName("setObjectA:"), (NSObject *)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("new")));
((void (*)(id, SEL, NSObject *))(void *)objc_msgSend)((id)self, sel_registerName("setObjectB:"), (NSObject *)((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("NSObject"), sel_registerName("new")));

__attribute__((objc_ownership(weak))) NSObject *weakObject = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("objectA"));
weakObject = ((NSObject *(*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("objectB"));

}

__attribute__((objc_ownership(weak)))id objc_initWeak(id *object, id value)
因为id本来就是带指针的,所以*id其实就是两个**,也就是weak指针的地址。

1
2
3
4
5
__weak NSObject *weakObject = self.objectA;
weakObject = self.objectB;

id objc_initWeak(**weakObject, self.objectA);
id objc_initWeak(**weakObject, self.objectB);

因为weakObject之前指向的是objectA, 所以

1
2
id objc_initWeak(**weakObject, self.objectA);
id objc_initWeak(**weakObject, self.objectB);
1
2
3
4
5
6
7
8
9
10
id
objc_initWeak(id *location, id newObj)
{
if (!newObj) {
*location = nil;
return nil;
}
return storeWeak<DontHaveOld, DoHaveNew, DoCrashIfDeallocating>
(location, (objc_object*)newObj);
}

storeWeak(location, (objc_object*)newObj)
storeWeak(NSObject **weakObject, (objc_object*)self.objectA)
storeWeak(NSObject **weakObject, (objc_object*)self.objectB)
这已经传入的是指向NSObject *指针的指针。
因为weakObject之前指向的是objectA,所以需要从objectA的sideTable中把weakObject删除,然后再把weakObject添加到objectB的SideTable。如果不删除的话,那么weakObject会在objectA销毁的时候会置为nill,但是这时候其实你已经把weakObject指向objectB了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
static id 
storeWeak(id *location, objc_object *newObj)
{
//location是weak指针修饰的指针的地址,而objc_object *newObj就是weak指针指向的对象。
assert(haveOld || haveNew);
if (!haveNew) assert(newObj == nil);

Class previouslyInitializedClass = nil;
id oldObj;
SideTable *oldTable;
SideTable *newTable;

// Acquire locks for old and new values.
// Order by lock address to prevent lock ordering problems.
// Retry if the old value changes underneath us.
retry:
// 如果weak指针之前弱引用过一个obj,则将这个 obj 所对应的 SideTable 取出,赋值给 oldTable
// 这里将对象当做Key就能取出之前的SideTale,SideTables是一个<StripedMap<SideTable>*>是一个对象为Key,SideTable为Values的字典。
// 如果这个对象之前有被弱应用过,则可以找到之前的SidesTable。
if (haveOld) {
oldObj = *location; //因为location本来就是一个指针,所以拿到location之前指向的对象的地址。
oldTable = &SideTables()[oldObj];
} else {
oldTable = nil;
}

//🌵🌵 这个地方感觉是要创建SideTables因为既然是新的值赋值给weak指针。
if (haveNew) {
newTable = &SideTables()[newObj];
} else {
newTable = nil;
}

//lockTwo 加锁,保证多线程安全
SideTable::lockTwo<haveOld, haveNew>(oldTable, newTable);

// 有无旧值 && location与oldObj 是否一致
// 🌵如果 有旧值 但 location与oldObj 不同,说明当前的location已经处理过oldObj,可是又被其他线程给修改了
if (haveOld && *location != oldObj) {
// 解锁, retry 重新处理 old
SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable);
goto retry;
}

// 通过确保弱引用的对象没有未初始化的isa,防止 弱引用 和 初始化 之间死锁
// 🌵这里为啥会导致死锁
// Prevent a deadlock between the weak reference machinery
// and the +initialize machinery by ensuring that no
// weakly-referenced object has an un-+initialized isa.
if (haveNew && newObj) {
Class cls = newObj->getIsa();
if (cls != previouslyInitializedClass &&
!((objc_class *)cls)->isInitialized())
{
SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable);
_class_initialize(_class_getNonMetaClass(cls, (id)newObj));

// If this class is finished with +initialize then we're good.
// If this class is still running +initialize on this thread
// (i.e. +initialize called storeWeak on an instance of itself)
// then we may proceed but it will appear initializing and
// not yet initialized to the check above.
// Instead set previouslyInitializedClass to recognize it on retry.
// cls 赋值给 previouslyInitializedClass 重新 retry
previouslyInitializedClass = cls;

goto retry;
}
}

// 如果weak指针之前弱引用过别的对象oldObj,则调用weak_unregister_no_lock,在oldObj的weak_entry_t中移除该weak指针地址
// Clean up old value, if any.
if (haveOld) {
weak_unregister_no_lock(&oldTable->weak_table, oldObj, location);
}

// Assign new value, if any.
if (haveNew) {
// 调用weak_register_no_lock方法,将weak指针的地址记录到newObj对应的weak_entry_t中
// weak_entry_t 插入到 全局 weak_table 哈希表中
newObj = (objc_object *)
weak_register_no_lock(&newTable->weak_table, (id)newObj, location,
crashIfDeallocating);
// weak_register_no_lock returns nil if weak store should be rejected

// 更新newObj的isa指针的weakly_referenced bit标志位
// Set is-weakly-referenced bit in refcount table.
if (newObj && !newObj->isTaggedPointer()) {
newObj->setWeaklyReferenced_nolock();
}

// Do not set *location anywhere else. That would introduce a race.
// 这里__weak修饰的指针location的值最终被赋值为newObj的值,而应用计数没有变化。
*location = (id)newObj;
}
else {
// No new value. The storage is not changed.
}

SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable);

return (id)newObj;
}