【发布时间】: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