前言
最近剛好學(xué)到了super的實(shí)現(xiàn)原理涧尿,然后心血來(lái)潮去試了一下系奉。在block中通過(guò)super調(diào)用父類的方法確實(shí)可能會(huì)造成循環(huán)引用。
實(shí)踐
@interface ViewController ()
@property (nonatomic, copy) void(^block)(void);
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.block = ^{
[super class];
};
}
@end
這時(shí)候我們?cè)赿ealloc里打上斷點(diǎn)姑廉,當(dāng)頁(yè)面離開(kāi)的時(shí)候缺亮。dealloc方法并沒(méi)有執(zhí)行。所以這里確實(shí)造成了循環(huán)引用
探究
當(dāng)使用[self class]時(shí)桥言,會(huì)調(diào)用objc_msgSend函數(shù)萌踱,第一個(gè)參數(shù)receiver就是self,而第二個(gè)參數(shù)号阿,要先找到self所在的這個(gè)class的方法列表并鸵,如果有,則返回對(duì)應(yīng)的selector并執(zhí)行扔涧,如果沒(méi)有园担,則會(huì)一層層向上尋找,直到找到為止枯夜,如果最后都沒(méi)能找到弯汰,ok,那我們進(jìn)入消息轉(zhuǎn)發(fā)流程卤档。
當(dāng)使用[super class]時(shí)蝙泼,會(huì)調(diào)用objc_msgSendSuper函數(shù)程剥,此時(shí)會(huì)先構(gòu)造一個(gè)objc_super的結(jié)構(gòu)體劝枣,然后第一個(gè)成員變量receiver仍然是self,而第二個(gè)成員變量super_class即是所在類的父類织鲸。構(gòu)造完之后舔腾,把結(jié)構(gòu)體傳入objc_msgSendSuper函數(shù)中,然后會(huì)從super_class這個(gè)類對(duì)應(yīng)的方法列表開(kāi)始找selector搂擦,如果有稳诚,則返回對(duì)應(yīng)的selector并執(zhí)行,如果沒(méi)有瀑踢,則會(huì)一層層向上尋找扳还,直到找到為止才避,如果最后都沒(méi)能找到,會(huì)進(jìn)入消息轉(zhuǎn)發(fā)流程氨距。
如此一探究桑逝,super調(diào)用的流程以及與self去調(diào)用的區(qū)別就真相大白了。現(xiàn)在再回頭來(lái)看示例中的block中調(diào)用super會(huì)導(dǎo)致循環(huán)引用的原因以及block如何安全使用super調(diào)用問(wèn)題的答案便已浮出水面了俏让。
objc_msgSendSuper(void /* struct objc_super *super, SEL op, ... */ )
注意:這里第一個(gè)參數(shù) 是一個(gè)objc_super的結(jié)構(gòu)體 這個(gè)結(jié)構(gòu)體的結(jié)構(gòu)為:
struct objc_super {
__unsafe_unretained _Nonnull id receiver;
__unsafe_unretained _Nonnull Class super_class;
};
結(jié)構(gòu)體第一個(gè)成員receiver 就代表方法的接受者 第二個(gè)成員代表方法接受者的父類
所以
self.block = ^{
[super class];
};
將super用源碼展開(kāi)后:
self.obj = ^{
struct objc_super superInfo = {
.receiver = self,
.super_class = class_getSuperclass(NSClassFromString(@"ViewController")),
};
((Class(*)(struct objc_super *, SEL))objc_msgSendSuper)(&superInfo,@selector(class));
};
可以很明顯的看到問(wèn)題楞遏,block強(qiáng)引用了self,而self也強(qiáng)持有了這個(gè)block首昔。
解決方法
正確的調(diào)用姿勢(shì)跟平常我們切斷block的循環(huán)引用的姿勢(shì)一模一樣:
__weak __typeof(self) weakSelf = self;
self.block = ^{
struct objc_super superInfo = {
.receiver = weakSelf,
.super_class = class_getSuperclass(NSClassFromString(@"ViewController")),
};
((Class(*)(struct objc_super *, SEL))objc_msgSendSuper)(&superInfo,@selector(class));
};
改完咱們?cè)僦匦翿un一下 寡喝,發(fā)現(xiàn)一切都正常了~