第二次尝试
到了这里,我们已经完全搞清楚了 oc 是如何管理assign
和weak
对象的了,如果你有兴趣也可以去自己尝试破解strong
的实现机制,原理一样。接下来我们决定开始对 MCAssignToWeak 进行第二次修改的尝试,这一次,我们需要加入对 delegate 属性的 setter 和 getter 的替换,使之调用正确的方法存取成员变量。
@implementation MCAssignToWeak (fixup)
+ (void)load {...}
- (void)fixup_setDelegate:(id)delegate {
Ivar ivar = class_getInstanceVariable([self class], "_delegate");
object_setIvar(self, ivar, delegate);
[self fixup_setDelegate:delegate]; // 最后调用原实现
}
- (id)fixup_delegate {
id del = [self fixup_delegate];
del = objc_loadWeak(&del);
return del;
}
@end
我们之所以在 fixup_setDelegate: 方法里,调用了 object_setIvar 而不是 objc_storeWeak 方法来设置弱引用到 _delegate,是因为 object_setIvar 里面需要先获取 Ivar 的 offset,然后将加上了偏移后的地址传入到 objc_storeWeak方法,同时 object_setIvar 还可以根据内存修饰符来调用与之相符的内存管理方法,这样写不仅能适应我们当前的assign
到weak
的需要,还可以满足以后其他类型之间互转的需要:
static ALWAYS_INLINE
void _object_setIvar(id obj, Ivar ivar, id value, bool assumeStrong)
{
if (!obj || !ivar || obj->isTaggedPointer()) return;
ptrdiff_t offset;
objc_ivar_memory_management_t memoryManagement;
_class_lookUpIvar(obj->ISA(), ivar, offset, memoryManagement);
if (memoryManagement == objc_ivar_memoryUnknown) {
if (assumeStrong) memoryManagement = objc_ivar_memoryStrong;
e