先看一下下面两段代码分别输出结果是什么:
1 ARC 环境下:
NSObject *obj = [[NSObject alloc] init];
id __autoreleasing o = obj;
NSLog(@"ARC:%d", _objc_rootRetainCount(obj));
2 MRC环境下:
NSObject *obj = [[NSObject alloc] init];
[obj autorelease];
NSLog(@"MRC:%d", obj .retainCount);
结果:
ARC:2
MRC:1
这里产生几个疑问:
1 Autoreleasepool里的对象不是用数组存的么?
2 为什么add到Autoreleasepool的对象引用计数没有发生变化?
3 ARC下为什么是2,而MRC下是1?
针对前两个问题, 查了一下资料《Pro.Multithreading.and.Memory.Management.for.iOS.and.OS.X》:
当你在mrc下调用 [obj autorelease];时,NSObject的autorelease方法的GNUstep实现是这样的:
- (id) autorelease {
[NSAutoreleasePool addObject:self];
}
- (void) addObject: (id)anObj {
[array addObject:anObj];
}
当然具体实现也是有优化的。
Apple的实现是这样的:
在AutoreleasePoolPage这个类里,
(可以看这里—》http://opensource.apple.com/source/objc4/objc4-493.11/runtime/objc-arr.mm)
static inline id autorelease(id obj) {
/* It corresponds to NSAutoreleasePool class method addObject. */
AutoreleasePoolPage *autoreleasePoolPage = /* getting active AutoreleasePoolPage object */
autoreleasePoolPage->add(obj);
}
id* add(id obj) {
assert(!full());
unprotect();
*next++ = obj;
protect();
return next-1;
}
我们可以看到实际上只是做了一个add操作,GNUstep addObject里的array实际上使用link list去实现的,而apple用的是一个动态数组,从上面的add方法的实现可以看出只有指针操作, 所以不会对引用计数造成影响。
第3个问题在arc下引用计数发生变化 是这一句id __autoreleasing o = obj;导致的。
这个可以参见这里:http://clang.llvm.org/docs/AutomaticReferenceCounting.html#ownership.semantics
其中有这样的描述:
“For __autoreleasing objects, the new pointer is retained, autoreleased, and stored into the lvalue using primitive semantics.”
也就是说上面的代码在arc下,编译器做转化的时候实际上会转化为:
id o = [obj retain] autorelease];
所以引用计数就变成2了。