[Objective-C]記憶體洩漏是新手必然要經歷的痛,NSMutableArray的正確使用
阿新 • • 發佈:2019-02-14
Objective-C程式開發中的記憶體洩漏問題是新手非常頭痛的事情,可能是用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方法也適用。
在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方法也適用。