基于OC中內(nèi)存管理的一些理解
下面是本人的一些理解
- 自己生成的對象雏亚,自己所持有
- 非自己生成的對象,自己也能持有
- 不再需要自己持有的對象時(shí)釋放
- 非自己持有的對象無法釋放
對象操作 | OC方法 |
---|---|
生成并持有對象 | alloc/new/copy/mutableCopy |
持有對象 | retain方法 |
釋放對象 | release方法 |
廢棄對象 | dealloc方法 |
這里解釋一下release方法和dealloc方法的區(qū)別
release方法主要是在MRC下釋放Foundation框架下面創(chuàng)建的對象狐史,在ARC下面是系統(tǒng)自動(dòng)的釋放
dealloc方法是釋放UIKit框架創(chuàng)建的UI界面的內(nèi)存
(小弟的理解就是這樣的,如果有錯(cuò)請大佬指點(diǎn)出來)
自己生成的對象说墨,自己所持有
使用以下名稱開頭的方法名意味著自己生成的對象只有自己持有
- alloc
- new
- copy
- mutableCopy
/*
*自己生成并持有的對象
*/
id obj = [[NSobject alloc]init];
/*
*這樣創(chuàng)建的對象引用計(jì)數(shù)+1
*/
非自己生成的對象骏全,自己也能持有
用上述方法以外取得的對象,即alloc/new/copy/mutableCopy以外的方法獲取的對象尼斧,因?yàn)榉亲约荷刹⒊钟薪保宰约翰皇窃搶ο蟮某钟姓撸热鏝SMutableArray類的array類方法創(chuàng)建的對象
/*
*取得非自己生成并持有的對象
*/
id obj = [NSMutableArray array];
/*
*源碼中棺棵,NSMutableArray類對象被賦給變量obj楼咳,但變量obj自己并沒有持有該對象。
*/
[obj retain];//obj對象的引用計(jì)數(shù)+1烛恤,調(diào)用retain方法之后就變?yōu)樽约核钟?
不再需要自己持有的對象時(shí)釋放
/*
*自己創(chuàng)建并持有的方法
*/
id obj = [NSObject new];
/*
*當(dāng)自己不需要的時(shí)候立即釋放
*/
[obj release]母怜;
非自己持有的對象無法釋放
對于自身創(chuàng)建的對象或者持有的對象,在不使用的時(shí)候必須釋放掉
倘若在程序中釋放了非自己所持有的對象程序就會(huì)崩潰
id obj = [NSObject new];
[obj release];
/*
*當(dāng)自身釋放了再次釋放之后系統(tǒng)就會(huì)崩潰
*/
[obj release];
ARC規(guī)則
在便以單位上缚柏,可設(shè)置ARC有效或者無效
一個(gè)應(yīng)用程序可以混合ARC有效或無效的二進(jìn)制形勢
設(shè)置ARC有效的編譯方式如下所示
- 使用clang(LLVM編譯器)3.0或以上版本
- 指定編譯器屬性為“-fobjc-arc”
當(dāng)然在Xcode4.2及以上的版本默認(rèn)設(shè)置的對所有的文件ARC有效
當(dāng)然MRC的內(nèi)存管理方式對于ARC一樣的適用苹熏,即: - 自己生成的對象,自己所持有
- 非自己生成的對象,自己也能持有
- 不再需要自己持有的對象時(shí)釋放
- 非自己持有的對象無法釋放
權(quán)限修飾符
- __strong
- __weak
- __unsafc_unretained
- __autoreleasing
__strong
__strong修飾符是id類型和對象類型默認(rèn)的所有權(quán)限修飾符轨域。也就是說袱耽,以下源代碼中的id變量,實(shí)際上被附加了所有權(quán)限修飾符
id obj = [[NSObject alloc]init];
id和對象類型在沒有明確指定所有權(quán)限修飾符時(shí)干发,默認(rèn)__strong修飾符朱巨,上面的源代碼與以下相同
id __strong obj = [[NSObject alloc]init];
該源代碼在ARC無效時(shí)的表述
/*ARC無效*/
id obj = [[NSObject alloc]init];
{
/*
*自己生成并且自己所持有
*/
id __strong obj = [[NSObject alloc]init];
}
//此源碼明確的指定了c語言的變量的作用域,ARC無效時(shí)铐然,該源代碼可描述如下:
/*ARC無效*/
{
id obj = [[NSObject alloc]init];
[obj release];
}
/*
*因?yàn)樽兞磕J(rèn)為__strong修飾,當(dāng)obj超出了其作用域恶座,強(qiáng)引用就會(huì)失效
*并且對象所有者不存在搀暑,因此廢棄該對象
*/
以上是__strong修飾符修飾的自己創(chuàng)建并且自己持有的對象的源碼分析
下面簡單的說一下非自己生成并持有對象的源碼
{
id __strong obj = [NSMutableArray array];
}
//在NSMutableArray類的array類方法的源碼中取得非自己生成并持有的對象
{
/*取得非自己生成并持有*/
id __strong obj = [NSMutableArray array];
/*
*因?yàn)樽兞縪bj是強(qiáng)引用,所以自己持有
*/
}
/*
*變量obj超出了作用域跨琳,強(qiáng)引用失效自点,自己釋放自己持有的對象
*/
其實(shí)附有__strong修飾符的變量之間可以相互賦值
id __strong obj0 = [[NSObject alloc]init];
id __strong obj1 = [[NSObject alloc]init];
id __strong obj2 = nill;
obj0 = obj1;
obj2 = obj0;
obj0 = nil;
obj1 = nil;
obj2 = nil;
當(dāng)然,即便是OC類成員變量脉让,也可以在方法參數(shù)上桂敛,使用附有__strong修飾符的變量
@interface Test : NSObject
{
id __strong obj_;
}
- (void)setObject:(id __strong)obj;
@end
@implementation Test
- (instancetype)init{
self = [super init];
if (self) {
}
return self;
}
- (void)setObject:(id __strong)obj{
obj_ = obj;
}
@end
正如蘋果粑粑說的那樣,通過__strong修飾符溅潜,不必再次鍵入retain和release术唬,滿足了“引用計(jì)數(shù)式管理的思考方式”
__weak
看起來好像通過__strong修飾符編譯器就能完美的進(jìn)行內(nèi)存管理,但是遺憾的是滚澜,僅通過__strong修飾符是不能解決有些重大的問題
這里所有的重大的問題就是引用計(jì)數(shù)式內(nèi)存管理中必然會(huì)發(fā)生的“循環(huán)引用”的問題
例如:前面我們的帶有__strong 的例子就容易發(fā)生循環(huán)引用
@interface Test : NSObject
{
id __strong obj_;
}
- (void)setObject:(id __strong)obj;
@end
@implementation Test
- (instancetype)init{
self = [super init];
if (self) {
}
return self;
}
- (void)setObject:(id __strong)obj{
obj_ = obj;
}
@end
//以下為循環(huán)引用
{
id test0 = [Test new];//對象A
id test1 = [Test new];//對象B
[test0 setObject: test1];//對象A的obj_成員變量持有對象B的強(qiáng)引用
[test1 setObject:test0];//對象B的obj_成員變量持有對象A的強(qiáng)引用
}
循環(huán)引用很容易造成內(nèi)存泄漏
上面這種情況是兩個(gè)相互強(qiáng)引用發(fā)生的內(nèi)存泄漏粗仓,下面這種是自身強(qiáng)引用自身發(fā)生的內(nèi)存泄漏
id test = [Test new];
[test setObject: test];
既然出現(xiàn)了這種強(qiáng)引用的內(nèi)存泄漏,那么蘋果粑粑就會(huì)解決這種內(nèi)存泄漏设捐,和__strong對應(yīng)的修飾符__weak借浊,如:
id __weak obj = [NSObject new];
變量obj上附加__weak修飾符,但是這樣編譯之后萝招,編譯器會(huì)發(fā)出警告
Assigning retained object to weak variable; object will be released after assignment
很顯然蚂斤,編譯器的意思就是很容易造成提前釋放,有問題就要解決
id __strong obj0 = [NSObject new];
id __weak obj1 = obj0槐沼;
這樣賦值就不會(huì)出現(xiàn)警告
當(dāng)然__weak還有一個(gè)優(yōu)點(diǎn)曙蒸,在持有某個(gè)對象的弱引用時(shí),若該對象被廢棄岗钩,則此弱引用將自動(dòng)失效且處于nil被賦值的狀態(tài),代碼如下:
id __weak obj1 = nil;
{
id __strong obj0 = [NSObject new];
obj1 = obj0;
NSLog(@"A:obj1:%@",obj1);
}
NSLog(@"B:obj1:%@",obj1);
此源碼執(zhí)行的結(jié)果:
A:obj1:<NSObject: 0x103000db0>
B:obj1:(null)
但是有個(gè)注意事項(xiàng):__weak修飾符只能用于iOS5以上及OS X Lion以上版本的應(yīng)用逸爵,在iOS4以下及OS X Snow Leopard 的應(yīng)用程序中可使用__unsafe _unretained 來修飾,但是對于現(xiàn)在來說也沒有多少人在使用iOS4以下及OS X Snow Leopard版本了
__unsafe _unretained
__unsafe _unretained 和__weak是相同的凹嘲,這里就不過多的講解师倔,但是要注意的是__unsafe _unretained是不安全的權(quán)限修飾符
__autoreleasing
ARC有效時(shí)不能使用autorelease和NSAutoreleasePool類,雖然autorelease無法直接使用,但是在ARC有效時(shí)autorelease功能是起作用的
/*ARC無效*/
NSAutoreleasePool *pool = [NSAutoreleasePool new];
id obj = [NSObject new];
[obj autorelease];
[pool drain];
/*ARC有效*/
@autoreleasepool {
id __autoreleasing obj = [NSObject new];
}
指定“@autoreleasepool代碼塊”來替代“ NSAutoreleasePool”
另外趋艘,在ARC有效時(shí)疲恢,要通過將對象賦值給附加了__autoreleasing修飾符的變量來替代調(diào)用autorelease方法,對象賦值給附有__autoreleasing修飾符的變量等價(jià)于ARC無效時(shí)調(diào)用對象的autorelease方法瓷胧,即對象被注冊到autoreleasepool
換一種說話就是在ARC有效時(shí)显拳,用@autoreleasepool塊替代NSAutoreleasePool類,用附有__autoreleasing修飾符的變量替代autorelease方法搓萧,圖解: