自从有了ARC,iOSer感觉得到了解放,再也不用考虑内存问题了,最多注意一下循环引用
iOS系统Framework很多地方对参数处理不统一。比如NSTimer强引用target,NSNotificationCenter是unsafe_assign,NSURLSession的delegate是retain等等
ARC通过分析代码,在合适的位置帮我们做内存管理。但是动态调用,就不能那么智能了。比如下面代码就会导致泄漏
- (void)test {
for (int i = 0; i < 4; i++) {
SEL sel = NSSelectorFromString(@"newData");
[self performSelector:sel];
}
return YES;
}
- (MYData *)newData {
MYData *data = [MYData new];
return data;
}
可以看一下newData的汇编代码(Product->Perform Action->Assembly)
.p2align 2
Lfunc_begin3:
.loc 17 62 0
.cfi_startproc
adrp x8, l_OBJC_CLASSLIST_REFERENCES_$_.35@PAGE
ldr x0, [x8, l_OBJC_CLASSLIST_REFERENCES_$_.35@PAGEOFF]
adrp x8, l_OBJC_SELECTOR_REFERENCES_.37@PAGE
ldr x1, [x8, l_OBJC_SELECTOR_REFERENCES_.37@PAGEOFF]
b _objc_msgSend
Lfunc_end3:
.cfi_endproc
ARC没有对返回的对象release,直接返回了。performSelector由于不知道返回的对象是什么,也不会它做任何操作,于是乎这个对象就泄漏了。
如果把newData改为getData,看看汇编代码有什么不同
.p2align 2 ;
Lfunc_begin4:
.cfi_startproc
stp x29, x30, [sp, #-16]! ; 8-byte Folded Spill
mov x29, sp
adrp x8, l_OBJC_CLASSLIST_REFERENCES_$_.35@PAGE
ldr x0, [x8, l_OBJC_CLASSLIST_REFERENCES_$_.35@PAGEOFF]
adrp x8, l_OBJC_SELECTOR_REFERENCES_.37@PAGE
ldr x1, [x8, l_OBJC_SELECTOR_REFERENCES_.37@PAGEOFF]
bl _objc_msgSend
ldp x29, x30, [sp], #16 ; 8-byte Folded Reload
b _objc_autoreleaseReturnValue
Lfunc_end4:
.cfi_endproc
多了一个_objc_autoreleaseReturnValue
调用。正是这个ARC插入的调用,将对象放入自动释放池,就不会出现泄漏。
OC有一套自己的命名规则,已new、copy,create开头的方法,默认都是调用方负责释放对象。所以,performSelector还是可以用的,就是要注意不要调用上面这种方法就可以了(官方建议使用NSInvocation代替)。
网友评论