arc和非arc下的retaincount问题

iOS 码拜 8年前 (2016-03-21) 958次浏览
下面的代码在
非arc下:obC = 1  ob1C = 2
在arc下:obC = 1  ob1C = 1
为什么在arc下  ob1C是1,本人觉得应该也是2啊,不是调用了setter吗?setter不是先release旧值,在retain新值的吗?
(_ob和ob1都是用strong声明的)
_ob = [[NSObject alloc] init];
self.ob1 = [[NSObject alloc] init];

NSInteger obC = CFGetRetainCount((__bridge CFTypeRef)_ob);
NSInteger ob1C = CFGetRetainCount((__bridge CFTypeRef)_ob1);

解决方案

50

其实是原因是你用 ARC 的话,编译器在 self.ob1 = [[NSObject alloc] init]; 之后就对 obj1 做了一次 release 了
代码如下:

#import <Foundation/Foundation.h>
@interface C : NSObject
@property (nonatomic, strong) NSObject *obj;
@property (nonatomic, strong) NSObject *obj1;
@end
@implementation C
- (instancetype)init {
	self = [super init];
	_obj = [[NSObject alloc] init];
	self.obj1 = [[NSObject alloc] init];
	NSInteger obC = CFGetRetainCount((__bridge CFTypeRef)_obj);
	NSInteger ob1C = CFGetRetainCount((__bridge CFTypeRef)_obj1);
	NSLog(@"%d, %d", obC, ob1C);
	return self;
}
@end
int main(int argc, char *argv[]) {
	@autoreleasepool {
		C *c = [[C alloc] init];
	}
}

我们来看类 C 的 init 方法的汇编代码
ARC 编译后得到的汇编代码(这里借助了下 Hopper 生成的伪码,帮助我们看懂汇编代码)

void * -[C init](void * self, void * _cmd) {
    rax = var_20;
    rax = [[rax super] init];
    var_8 = rax;
    objc_storeStrong(0x0, rax);
    rax = [NSObject alloc];
    rax = [rax init];
    rcx = var_8->_obj;
    var_8->_obj = rax;
    [rcx release];
    rax = [NSObject alloc];
    rax = [rax init];
    var_40 = rax;
    [var_8 setObj1:rax];
    [var_40 release];
    NSLog(@"%d, %d", CFGetRetainCount(var_8->_obj), CFGetRetainCount(var_8->_obj1));
    var_48 = [var_8 retain];
    objc_storeStrong(var_8, 0x0);
    rax = var_48;
    return rax;
}

可以看到 set 完成后,都调用了一次 release,所以后面输出的结果是1,1
相对的非 ARC 的汇编代码如下:

void * -[C init](void * self, void * _cmd) {
    rax = var_20;
    var_8 = [[rax super] init];
    var_8->_obj = [[NSObject alloc] init];
    rax = [NSObject alloc];
    rax = [rax init];
    [var_8 setObj1:rax];
    NSLog(@"%d, %d", CFGetRetainCount(var_8->_obj), CFGetRetainCount(var_8->_obj1));
    rax = var_8;
    return rax;
}

可以看到对象在创建后丢给了 set 方法,Retain Count +1,但是在之后并没有调用 release 方法,所以这里输出的结果就是1,2了


CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明arc和非arc下的retaincount问题
喜欢 (0)
[1034331897@qq.com]
分享 (0)