該文檔不指定initWithArray是否將舊數組(prefs)中的對象添加到新數組(userAdded)時發送額外的保留。它應該,因爲項目被添加到新陣列。也許當舊數組(prefs)被釋放時,userAdded中元素的保留計數太低,對象也被釋放,並且應用程序崩潰。爲了檢查這個問題,我在調用initWithArray之前和之後詢問了第一個數組的內容。
NSUserDefaults *myDefault = [NSUserDefaults standardUserDefaults];
NSArray *prefs = [myDefault arrayForKey:@"addedPrefs"];
NSUInteger i, count = [prefs count];
for (i = 0; i < count; i++) {
NSObject * obj = [prefs objectAtIndex:i];
NSLog(@"Object: %@, Retain count: %d.", obj, [obj retainCount]);
}
userAdded = [[NSMutableArray alloc] initWithArray:prefs];
for (i = 0; i < count; i++) {
NSObject * obj = [prefs objectAtIndex:i];
NSLog(@"Object: %@, Retain count: %d.", obj, [obj retainCount]);
}
對象報告增加的保留計數,因此可以釋放prefs數組而不影響新數組。但是運行這個代碼仍然會泄漏一個NSArray。
所以這個問題必須存在於prefs數組中。由於NSUserDelfaults方法arrayForKey:產生prefs數組,但在這個方法的名字中沒有找到「alloc」,「new」或「copy」等字,調用方法不擁有prefs數組。最有可能的是,prefs數組被添加到autorelease池中。爲了測試這個想法,我將上述測試代碼與NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
和[pool drain]
的調用進行了包圍。運行此代碼不會泄漏數組。
所以我認爲prefs數組正在被添加到一個自動釋放池不排水。消除這種泄漏的最簡單方法是在創建prefs數組之前創建自動釋放池,並在使用prefs數組完成時清除該池。
我們不知道'initWithArray:'的內部工作原理,它不如''保留'給出的'NSArray',所以在試圖理解保留計數時存在危險。 (我想:爲什麼不這樣做,因爲'NSArray'是不可變的?它可以跟蹤對'NSArray'的更改,或者僅在寫入時自己創建副本或類似的東西。) – mvds 2010-07-19 13:36:56
「文檔沒有指定initWithArray是否將舊數組(prefs)中的對象添加到新數組時添加額外的保留。數組總是保留其元素 - 或者做一些事情來阻止它們被釋放。 – JeremyP 2010-07-19 15:20:47
現在我很困惑。 我應該使用上述問題中描述的最後一種方法嗎? userAdded = [[NSMutableArray alloc]等copyItems:YES]; – jarryd 2010-07-19 15:25:55