【问题标题】:iOS How ARC insert codes?iOS ARC如何插入代码?
【发布时间】:2015-02-07 02:20:28
【问题描述】:

我正在阅读 ARC 的一些深度实现, 通过阅读xcode生成的汇编代码,我们可以看到编译器插入了类似objc_release、objc_storeStrong之类的代码。

如果我们有这样的代码:

-(void)foo
{
   NSDate * _date = [[NSDate alloc] init]; 
}

汇编代码如下:

movq    %rdi, -32(%rbp)         ## 8-byte Spill
movq    %rsi, %rdi
movq    -32(%rbp), %rsi         ## 8-byte Reload
callq   _objc_msgSend   (this is call of 'alloc')
movq    L_OBJC_SELECTOR_REFERENCES_2(%rip), %rsi
movq    %rax, %rdi
callq   _objc_msgSend   (this is call of 'init')
movq    %rax, -24(%rbp)
.loc    1 30 0   

并且在 { } 的末尾,编译器插入 _objc_storeStrong

movq    %rdx, %rdi
callq   _objc_storeStrong  (in this _objc_storeStrong, _date is released)
addq    $64, %rsp
popq    %rbp
retq

编译 _objc_storeStrong(_date,nil);因为没有人拥有 Date 变量。

有道理

然后我这样写:日期成为一个强成员变量

@interface MyView : UIView
@property(nonatomic,strong) NSDate * date;
@end

-(void)foo
{
   self.date = [[NSDate alloc] init]; 
}

汇编代码是:

movq    %rax, -48(%rbp)         ## 8-byte Spill
callq   _objc_msgSend  (call alloc)
movq    L_OBJC_SELECTOR_REFERENCES_2(%rip), %rsi
movq    %rax, %rdi
callq   _objc_msgSend  (call init)
movq    L_OBJC_SELECTOR_REFERENCES_4(%rip), %rsi
movq    -48(%rbp), %rdi         ## 8-byte Reload
movq    %rax, %rdx
movq    %rax, -56(%rbp)         ## 8-byte Spill
callq   _objc_msgSend  (call setDate:)
movq    -56(%rbp), %rax         ## 8-byte Reload
movq    %rax, %rdi
callq   _objc_release  ( a magic release,~!!!)

基本上,setDate 将保留日期,最后一行释放它以平衡。(不是它,见下面的测试)

然后我把代码改成

@interface MyView : UIView
@property(nonatomic,strong) NSDate * date;
@end

-(void)foo
{
   _date = [[NSDate alloc] init]; 
}

汇编代码变成

callq   _objc_msgSend (call alloc)
movq    L_OBJC_SELECTOR_REFERENCES_2(%rip), %rsi
movq    %rax, %rdi
callq   _objc_msgSend (call init)
movq    -8(%rbp), %rsi
movq    _OBJC_IVAR_$_MyView._date(%rip), %rdi (set date directly)
movq    (%rsi,%rdi), %rcx
movq    %rax, (%rsi,%rdi)
movq    %rcx, %rdi
callq   _objc_release ( a magic release? here? why, we didn't retain it? )

编译器也插入了一个_objc_release,为什么?我们这里没有添加任何保留代码,

这真是迷惑了我一天,经过测试,_date实际上并没有发布,你可以使用它。

我在 objc_release 上添加了一个符号断点来跟踪保留计数, 如果我们使用 self.date = [[NSDate alloc] init],objc_release 中断 2 次, 通过检查retain count(CFGetRetainCount),retainCount是2再1,是正确的。

如果使用 _date = [[NSDate alloc] init],objc_release 只中断一次,retainCount 为 1。

有人可以帮助我理解这一点吗?

还有一个问题,符号点,我使用lldb上的寄存器读取来读取第一个寄存器内容,并打印保留计数,是否正确?通常 r0 r1 r2 包含方法的参数。

【问题讨论】:

    标签: ios objective-c automatic-ref-counting


    【解决方案1】:

    编译器应该释放ARC环境下__strong变量中存储的旧值。

    _date = [[NSDate alloc] init];
    

    在这种情况下,_date 变量的值应该被释放。因此,编译器发出如下代码。

    NSDate *newDate = [[NSDate alloc] init];
    NSDate *oldDate = _date;
    _date = newDate;
    [oldDate release];
    

    callq _objc_release 用于释放 oldDate 值。

    【讨论】:

      猜你喜欢
      • 2019-05-12
      • 2012-02-16
      • 1970-01-01
      • 1970-01-01
      • 2022-12-11
      • 1970-01-01
      • 2019-11-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多