iPhone程序開發中的內存泄漏問題是新手非常頭痛的事情,可能是用C#這類自動垃圾釋放的語言太習慣了,用xcode中的profile工具查了一下我寫的小程序,內存泄漏了一大堆,經過一陣子排查,在NSMutableArray中添加對象後不正確維護對象的引用計數是一個主要原因。
在NSMutableArray how to properly addObjects and release這個討論主題中,給出了正確的使用NSMutableArray的步驟,先看他給出的代碼。
NSMutableArray *listData = [[NSMutableArray alloc] init];
for (int i = 0; i < 3; i++) {
MyData *obj = [[MyData alloc] init];
NSString *name = nil;
switch (i) {
case 0:
name = @"Semen";
break;
case 1:
name = @"Ivan";
break;
case 2:
name = @"Stepan";
break;
default:
break;
}
obj.name = name;
[listData addObject: obj];
[obj release];
}
[listData release];
裏面提到了3個問題,翻譯後加上我的理解:
(1)NSMutableArray這個數組裏麪包含的對象是什麼?是對象的一份拷貝,還只是一個對象的指針?
答:數組裏存放的不是對象的複本,只是對象的指針。
按以前所學的C++的思維方式,上面的這句[obj release]是最難理解的,我把obj放在數組裏,數組裏存放的是對象的引用,爲什麼把obj釋放了?這樣數組裏存放了一個無效的指針?實際上還是思維方式沒有轉變過來,在Objective-C中,[obj release]只表示obj收到一個release消息,如果它的引用計數沒有變成0,它就不會釋放,而在C++中見到這個release就想到了釋放。我們來看一個過程:
MyData *obj = [[MyData alloc] init]; //obj用了init方法,按照約定,obj的引用計數是1,並且要自已來維護釋放過程
[listData addObject: obj]; //obj在放到數組裏的時候會自動給obj的引用計數加1,這時obj的引用計數就是2
[obj release]; //爲了維持obj的正常計數值,用這條語句讓obj的引用計數爲1,僅此而已,並沒有被釋放掉!
[listData release]; // 這句會給obj再發一個release消息,這樣obj的引用計數變爲0,銷燬。如果前面那條語句[obj release]不寫,則obj的對象沒有正常釋放掉,就會造成內存泄漏!
(2)需要先釋放掉數組裏的所有對象,然後再釋放NSMutableArray對象嗎?
答:不需要。
在釋放NSMutableArray對象裏,它自動先給裏面的對象發一個release消息。
(3)正確使用NSMutableArray的步驟是什麼? (alloc, init, work, release)
答:
1. NSMutableArray *arr = [[NSMutableArray alloc] init]; //分配數組
2. alloc object1. //分配obj1
3. add object1 to array. //把obj1加到數組中
4. release object1. //obj1引用計數減1
5. alloc object2. //分配obj2
6. add object2 to array. //把obj2加到數組中
7. release object2. //obj2引用計數減1
8. add as many objects as needed in this manner. // 按上面的辦法,可以加任意多的對象
8. work with object1. //可以訪問裏面的對象
9. remove object1 from array. it will receive a release automatically. //也可以把obj1移除,這時obj1會自動收到一個release消息
10. [arr release]; // object2 and others will receive a release. 最後釋放數組,數組裏的所有元素也會自動得到一個release消息
上述道理對於NSMutableDictionary類的setObject方法也適用。