我們都知道iOS中采用引用計數的技術來管理內存,當一個對象沒有任何一個地方引用的時候會自動釋放,此時的retainCount為0,而且提供瞭一個-(NSInteger)retainCount的方法來獲得對象當前的持有數。
這個概念清楚而明確,不過,讓我們看兩段代碼:
NSNumber *number = [NSNumber numberWithInt:1]; NSLog(@"retainCount = %lu",[number retainCount]);
這段代碼的運行結果是什麼?
NSString *string = [NSString stringWithFormat:@"foo"]; NSLog(@"retainCount = %lu", [string retainCount]);
這一段呢?
在Xcode5.0, ARC關閉的情況下運行,結果是:
2014-01-13 22:08:13.217 blockTest[2732:303] retainCount = 9223372036854775807
2014-01-13 22:08:13.218 blockTest[2732:303] retainCount = 1
這個很出人意料啊,第二段看上去很符合我們的預期,但第一段就有點讓人掉眼鏡瞭。
查閱瞭一下官方的文檔,第一句就是“Do not use this method.”,後面給出瞭說明,因為Autorelease pool的存在,對於內存的管理會相當復雜,retainCount就不能用作調試內存時的依據瞭。這樣對於第一段的結果就可以理解瞭,可能系統對於這一個特殊的對象有特殊的處理(沒準framework裡面有早就創建瞭這個對象瞭),於是我們拿到瞭一個非常出人意料的結果。
想想見過的如下的代碼就很有點嚇人瞭:
while ([a retainCount] > 0) { [a release]; }
如果運行結果正確,那麼這是多麼幸運的一個人啊!
但對於內存的思考我們可以更進一步,看一段代碼:
#import @interface Person : NSObject @property(nonatomic, retain) NSString *name; @property(nonatomic, assign) NSInteger age; @end @implementation Person - (id)init { self = [super init]; if (self) { self.name = @"name"; self.age = 20; } return self; } - (void)dealloc { NSLog(@"dealloc"); [super dealloc]; } @end int main(int argc, const char * argv[]) { Person *per1 = [[Person alloc] init]; //NSLog(@"retainCount = %lu -- 0",[per1 retainCount]); [per1 release]; per1.age = 22; NSLog(@"retainCount = %lu -- 1, age = %ld",[per1 retainCount], per1.age); //[per1 retain]; //per1.age = 23; //NSLog(@"retainCount = %lu -- 2, age = %ld",[per1 retainCount], per1.age); return 0; }
這段代碼的運行結果居然是:
2014-01-13 22:17:11.619 blockTest[2758:303] dealloc
2014-01-13 22:17:11.621 blockTest[2758:303] retainCount = 1 — 1, age = 22
這個問題位於https://www.cocoachina.com/ask/questions/show/106777#36483,個人猜測是對象確實銷毀瞭,畢竟dealloc都調用瞭,但內存裡面數據仍然存在,立刻打印是存在內容的,至於retainCount不是0,隻能說明對象即使已經銷毀瞭,這個值仍然可能大於0。