Dark Corner In ARC

2018-12-21  本文已影响9人  偶是星爷

自从有了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代替)。

上一篇 下一篇

猜你喜欢

热点阅读