關于iOS內存管理的規則思考
關于iOS內存管理的規則思考
- 自己生成的生成的對象,自己持有。
- 非自己生成的對象,自己也能持有。
- 不在需要自己持有的對象時釋放。
- 非自己持有的對象無法釋放。
注:這里的自己是對象使用的環境,理解為編程人員本身也沒有錯
對象操作和Objective-C方法對應
對象操作 | Objectivew-C方法 |
---|---|
生成并持有對象 | alloc/copy/mutableCopy/new或以此開頭的方法 |
持有對象 | retain |
釋放對象 | release |
廢棄對象 | dealloc |
自己生成的對象,自己持有
//自己生成并持有對象
id obj1 = [[NSObject alloc] init];
id obj2 = [NSObject new];
id obj3 = [obj2 copy];</code></pre>
copy 方法基于NSCopying方法約定,實現類中的 copyWithZone:
mutableCopy 方法基于NSMutableCopying方法約定,實現類中的 mutableCopyWithZone:
非自己生成的對象,自己也能持有
用alloc/new/copy/mutableCopy以外的方法取得的對象,自己不是該對象的持有者。
//取的非自己生成并持有的對象,
//取得對象的存在,但自己不持有對象。
id obj = [NSMutableArray array];
id obj2 = [NSDictionary dictionary];
//自己持有對象
[obj retain];
[obj2 retain];</code></pre>
注:這里有點不好理解,我們先來看一段代碼:
//取的非自己生成并持有的對象,
//取得對象的存在,但自己不持有對象。
id unretain_obj = [NSMutableArray array];
NSLog(@"unretain_obj retain count = %lu", (unsigned long)[unretain_obj retainCount]);
//調用 release
[unretain_obj release];</code></pre>
上述代碼,我們打印結果是:
2016-12-21 15:32:04.485 acm[65216:852108] unretain_obj retain count = 1
隨后調用 release 方法會導致程序崩潰!
按照引用計數來說,這時 unretain_obj 是可以被執行一次release方法的。但是為什么我們直接調用會導致程序崩潰。
我們會想最開始提到的四條思想之一:
無法釋放非自己持有的對象
這樣我們就很好理解了。雖然打印出 unretain_obj 的 retainCount 為 1 但是不能說明是因為它引用了對象。它只是單純的獲取到了對象的存在而已。
那么我們會產生一個問題。那么這個對象是誰在持有??
我們先做一個猜測:
因為 [NSMutableArray array] 是一個工廠方法,在 array 肯定是要生成一個 NSMutableArray 實例對象。這時也必然會有一個指針引用它然后返回這個對象。so。。。
先想到這里,后邊我們再去印證
我們再來看一段代碼:
//取的非自己生成并持有的對象,
//取得對象的存在,但自己不持有對象。
id unretain_obj = [NSMutableArray array];
NSLog(@"unretain_obj retain count = %lu", (unsigned long)[unretain_obj retainCount]);
//自己持有對象
[unretain_obj retain];
NSLog(@"unretain_obj retain count = %lu", (unsigned long)[unretain_obj retainCount]);
//釋放自己持有的對象
[unretain_obj release];
NSLog(@"unretain_obj retain count = %lu", (unsigned long)[unretain_obj retainCount]);</code></pre>
打印結果
2016-12-21 15:40:20.774 acm[65682:861135] unretain_obj retain count = 1
2016-12-21 15:40:20.774 acm[65682:861135] unretain_obj retain count = 2
2016-12-21 15:40:25.254 acm[65682:861135] unretain_obj retain count = 1
并且程序也不會崩潰。
著也印證了我們上邊的想法。
因為通過 retain 方法,非自己生成的對象跟用alloc/new/copy/mutableCopy方法生成并持有的對象一樣,成了自己所持有的
不在需要自己持有的對象時釋放
通過上邊的例子我們知道,自己持有的對象在釋放時調用release方法,eg:
//自己生成并持有對象
id release_obj = [[NSObject alloc] init];
//將自己持有的對象釋放
[release_obj release];
/*
- 釋放對象
- 指向對象的指針依然被保留在變量release_obj 中,你依然可以調用它。
- 但是對象一經釋放絕對不可訪問,否則會造成程序崩潰。
出現EXC_BAD_ACCESS Crash問題
*/</code></pre>
我們自己實現一個方法,返回一個方法調用著也可以持有的對象,即alloc的作用
- (id)allocObject {
//自己生成并持有對象
id obj = [[NSObject alloc] init];
//原封不動的返回一個由alloc方法生成的對象
return obj;
}
注:方法名符合 生成并持有對象 alloc/copy/mutableCopy/new或以此開頭的方法 規則
我們自己實現一個方法,返回一個誰也不持有的對象,只是取得對象的存在
- (id)object {
//自己生成并持有對象
id obj = [[NSObject alloc] init];
//調用autorelease方法 取得對象的存在,但自己不持有對象。
[obj autorelease];
return obj;
}
autorelease 方法可以取得對象的存在,但自己不持有對象。使對象在超出指定的生存范圍時能夠自動的并正確的釋放(調用 release 方法)
autorelease和release方法的區別
autorelease:
release:
autorelease的詳細解說我們后邊介紹。
我們也可以通過調用 retain 方法來使 autorelease 方法的來的對象自己持有eg:
//獲取對象的存在,自己不持有
id unretain_obj = [NSMutableArray array];
//持有對象
[unretain_obj retain];
無法釋放非自己持有的對象
自己已經釋放了還繼續釋放
//自己生成并持有對象
id release_obj = [[NSObject alloc] init];
//將自己持有的對象釋放
[release_obj release];
//釋放已經釋放的對象
[release_obj release];
/*
* 釋放對象
* 指向對象的指針依然被保留在變量release_obj 中,你依然可以調用它。
* 但是對象一經釋放絕對不可訪問,否則會造成程序崩潰。
* 出現EXC_BAD_ACCESS Crash問題
*/
只獲取了對象的存在,試圖釋放對象
//取的非自己生成并持有的對象,
//取得對象的存在,但自己不持有對象。
id unretain_obj = [NSMutableArray array];
//釋放自己不持有的對象
[unretain_obj release];
程序崩潰,報EXC_BAD_ACCESS Crash問題
來自:http://blog.csdn.net/wxs0124/article/details/53787357