先看一下下面兩段代碼分别輸出結果是什麼:
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了。