最近老問(wèn)這個(gè)堕伪,但是每個(gè)人的理解不一樣,其實(shí)我也不知道應(yīng)該咋說(shuō)
*基本概念
引用計(jì)數(shù)(Reference Count)
*內(nèi)存釋放的原則
手動(dòng)管理內(nèi)存有時(shí)候并不容易它浅,因?yàn)閷?duì)象的引用有時(shí)候是錯(cuò)綜復(fù)雜的玖翅,對(duì)象之間可能互相交叉引用唐全,此時(shí)需要遵循一個(gè)法則:誰(shuí)創(chuàng)建,誰(shuí)釋放接癌。
*自動(dòng)釋放池
在ObjC中也有一種內(nèi)存自動(dòng)釋放的機(jī)制叫做“自動(dòng)引用計(jì)數(shù)”(或“自動(dòng)釋放池”)心赶,與C#、Java不同的是缺猛,這只是一種半自動(dòng)的機(jī)制缨叫,有些操作還是需要我們手動(dòng)設(shè)置的。自動(dòng)內(nèi)存釋放使用@autoreleasepool關(guān)鍵字聲明一個(gè)代碼塊荔燎,如果一個(gè)對(duì)象在初始化時(shí)調(diào)用了autorelase方法耻姥,那么當(dāng)代碼塊執(zhí)行完之后,在塊中調(diào)用過(guò)autorelease方法的對(duì)象都會(huì)自動(dòng)調(diào)用一次release方法有咨。這樣一來(lái)就起到了自動(dòng)釋放的作用琐簇,同時(shí)對(duì)象的銷毀過(guò)程也得到了延遲(統(tǒng)一調(diào)用release方法)
在開(kāi)發(fā)中,我們常常都會(huì)使用到局部變量座享,局部變量一個(gè)特點(diǎn)就是當(dāng)它超過(guò)作用域時(shí)婉商,就會(huì)自動(dòng)釋放。而autorelease pool跟局部變量類似渣叛,當(dāng)執(zhí)行代碼超過(guò)autorelease pool塊時(shí)丈秩,所有放在autorelease pool的對(duì)象都會(huì)自動(dòng)調(diào)用release。它的工作原理如下:
創(chuàng)建一個(gè)NSAutoreleasePool對(duì)象
在autorelease pool塊的對(duì)象調(diào)用autorelease方法
釋放NSAutoreleasePool對(duì)象
對(duì)于自動(dòng)內(nèi)存釋放簡(jiǎn)單總結(jié)一下:
autorelease方法不會(huì)改變對(duì)象的引用計(jì)數(shù)器淳衙,只是將這個(gè)對(duì)象放到自動(dòng)釋放池中蘑秽;
自動(dòng)釋放池實(shí)質(zhì)是當(dāng)自動(dòng)釋放池銷毀后調(diào)用對(duì)象的release方法挽唉,不一定就能銷毀對(duì)象(例如如果一個(gè)對(duì)象的引用計(jì)數(shù)器>1則此時(shí)就無(wú)法銷毀);
由于自動(dòng)釋放池最后統(tǒng)一銷毀對(duì)象筷狼,因此如果一個(gè)操作比較占用內(nèi)存(對(duì)象比較多或者對(duì)象占用資源比較多)瓶籽,最好不要放到自動(dòng)釋放池或者考慮放到多個(gè)自動(dòng)釋放池;
ObjC中類庫(kù)中的靜態(tài)方法一般都不需要手動(dòng)釋放埂材,內(nèi)部已經(jīng)調(diào)用了autorelease方法
ARC管理方法
iOS/OS X內(nèi)存管理方法有兩種:手動(dòng)引用計(jì)數(shù)(Manual Reference Counting)和自動(dòng)引用計(jì)數(shù)(Automatic Reference Counting)塑顺。從OS X Lion和iOS 5開(kāi)始,不再需要程序員手動(dòng)調(diào)用retain和release方法來(lái)管理Objective-C對(duì)象的內(nèi)存俏险,而是引入一種新的內(nèi)存管理機(jī)制Automatic Reference Counting(ARC)严拒,簡(jiǎn)單來(lái)說(shuō),它讓編譯器來(lái)代替程序員來(lái)自動(dòng)加入retain和release方法來(lái)持有和放棄對(duì)象的所有權(quán)竖独。
在ARC內(nèi)存管理機(jī)制中裤唠,id和其他對(duì)象類型變量必須是以下四個(gè)ownership qualifiers其中一個(gè)來(lái)修飾:
__strong(默認(rèn),如果不指定其他莹痢,編譯器就默認(rèn)加入)
__weak
__unsafe_unretained
__autoreleasing
所以在管理Objective-C對(duì)象內(nèi)存的時(shí)候种蘸,你必須選擇其中一個(gè),下面會(huì)用一些列子來(lái)逐個(gè)解釋它們的含義以及如何選擇它們竞膳。
__strong ownership qualifier
如果我想創(chuàng)建一個(gè)字符串航瞭,使用完之后將它釋放調(diào)用
{
NSString *text = [[NSString alloc] initWithFormat:@"Hello, world"]; //@"Hello, world"對(duì)象的RC=1
NSLog(@"%@", text);
[text release]; //@"Hello, world"對(duì)象的RC=0
}
而如果是使用ARC方式的話,就text對(duì)象無(wú)需調(diào)用release方法坦辟,而是當(dāng)text變量超過(guò)作用域時(shí)刊侯,編譯器來(lái)自動(dòng)加入[text release]方法來(lái)釋放內(nèi)存
{
NSString *text = [[NSString alloc] initWithFormat:@"Hello, world"]; //@"Hello, world"對(duì)象的RC=1
NSLog(@"%@", text);
}
/*
* 當(dāng)text超過(guò)作用域時(shí),@"Hello, world"對(duì)象會(huì)自動(dòng)釋放锉走,RC=0
*/
而當(dāng)你將text賦值給其他變量anotherText時(shí)滨彻,MRC需要retain一下來(lái)持有所有權(quán),當(dāng)text和anotherText使用完之后挪蹭,各個(gè)調(diào)用release方法來(lái)釋放亭饵。
{
NSString *text = [[NSString alloc] initWithFormat:@"Hello, world"]; //@"Hello, world"對(duì)象的RC=1
NSLog(@"%@", text);
NSString *anotherText = text; //@"Hello, world"對(duì)象的RC=1
[anotherText retain]; //@"Hello, world"對(duì)象的RC=2
NSLog(@"%@", anotherText);
[text release]; //@"Hello, world"對(duì)象的RC=1
[anotherText release]; //@"Hello, world"對(duì)象的RC=0
}
而使用ARC的話,并不需要調(diào)用retain和release方法來(lái)持有跟釋放對(duì)象嚣潜。
{
NSString *text = [[NSString alloc] initWithFormat:@"Hello, world"]; //@"Hello, world"對(duì)象的RC=1
NSLog(@"%@", text);
NSString *anotherText = text; //@"Hello, world"對(duì)象的RC=2
NSLog(@"%@", anotherText);
}
/*
* 當(dāng)text和anotherText超過(guò)作用域時(shí)冬骚,會(huì)自動(dòng)調(diào)用[text release]和[anotherText release]方法, @"Hello, world"對(duì)象的RC=0
*/
除了當(dāng)__strong變量超過(guò)作用域時(shí)懂算,編譯器會(huì)自動(dòng)加入release語(yǔ)句來(lái)釋放內(nèi)存只冻,如果你將__strong變量重新賦給它其他值,那么編譯器也會(huì)自動(dòng)加入release語(yǔ)句來(lái)釋放變量指向之前的對(duì)象计技。例如:
{
NSString *text = [[NSString alloc] initWithFormat:@"Hello, world"]; //@"Hello, world"對(duì)象的RC=1
NSString *anotherText = text; //@"Hello, world"對(duì)象的RC=2
NSString *anotherText = [[NSString alloc] initWithFormat:@"Sam Lau"]; // 由于anotherText對(duì)象引用另一個(gè)對(duì)象@"Sam Lau"喜德,那么就會(huì)自動(dòng)調(diào)用[anotherText release]方法,使得@"Hello, world"對(duì)象的RC=1, @"Sam Lau"對(duì)象的RC=1
}
/*
* 當(dāng)text和anotherText超過(guò)作用域時(shí)垮媒,會(huì)自動(dòng)調(diào)用[text release]和[anotherText release]方法舍悯,
* @"Hello, world"對(duì)象的RC=0和@"Sam Lau"對(duì)象的RC=0
*/
如果變量var被__strong修飾航棱,當(dāng)變量var指向某個(gè)對(duì)象objc,那么變量var持有某個(gè)對(duì)象objc的所有權(quán)
前面已經(jīng)提過(guò)內(nèi)存管理的四條規(guī)則:
我們總結(jié)一下編譯器是按以下方法來(lái)實(shí)現(xiàn)的:
對(duì)于規(guī)則1和規(guī)則2萌衬,是通過(guò)__strong變量來(lái)實(shí)現(xiàn)饮醇,
對(duì)于規(guī)則3來(lái)說(shuō),當(dāng)變量超過(guò)它的作用域或被賦值或成員變量被丟棄時(shí)就能實(shí)現(xiàn)
對(duì)于規(guī)則4秕豫,當(dāng)RC=0時(shí)朴艰,系統(tǒng)就會(huì)自動(dòng)調(diào)用
__weak ownership qualifier
其實(shí)編譯器根據(jù)__strong修飾符來(lái)管理對(duì)象內(nèi)存。但是__strong并不能解決引用循環(huán)(Reference Cycle)問(wèn)題:對(duì)象A持有對(duì)象B混移,反過(guò)來(lái)祠墅,對(duì)象B持有對(duì)象A;這樣會(huì)導(dǎo)致不能釋放內(nèi)存造成內(nèi)存泄露問(wèn)題歌径。
引用Pro Multithreading and Memory Management for iOS and OS X的圖
舉一個(gè)簡(jiǎn)單的例子毁嗦,有一個(gè)類Test有個(gè)屬性objc,有兩個(gè)對(duì)象test1和test2的屬性objc互相引用test1和test2:
@interface Test : NSObject
@property (strong, nonatomic) id objc;
@end
{
Test *test1 = [Test new]; /* 對(duì)象a */
/* test1有一個(gè)強(qiáng)引用到對(duì)象a */
Test *test2 = [Test new]; /* 對(duì)象b */
/* test2有一個(gè)強(qiáng)引用到對(duì)象b */
test1.objc = test2; /* 對(duì)象a的成員變量objc有一個(gè)強(qiáng)引用到對(duì)象b */
test2.objc = test1; /* 對(duì)象b的成員變量objc有一個(gè)強(qiáng)引用到對(duì)象a */
}
/* 當(dāng)變量test1超過(guò)它作用域時(shí)回铛,它指向a對(duì)象會(huì)自動(dòng)release
* 當(dāng)變量test2超過(guò)它作用域時(shí)狗准,它指向b對(duì)象會(huì)自動(dòng)release
* 此時(shí),b對(duì)象的objc成員變量仍持有一個(gè)強(qiáng)引用到對(duì)象a
* 此時(shí)勺届,a對(duì)象的objc成員變量仍持有一個(gè)強(qiáng)引用到對(duì)象b
* 于是發(fā)生內(nèi)存泄露
*/
如何解決驶俊?于是我們引用一個(gè)__weakownership qualifier,被它修飾的變量都不持有對(duì)象的所有權(quán)免姿,而且當(dāng)變量指向的對(duì)象的RC為0時(shí),變量設(shè)置為nil榕酒。例如:
__weak NSString *text = [[NSString alloc] initWithFormat:@"Sam Lau"];
NSLog(@"%@", text);
由于text變量被__weak修飾胚膊,text并不持有@"Sam Lau"對(duì)象的所有權(quán),@"Sam Lau"對(duì)象一創(chuàng)建就馬上被釋放想鹰,并且編譯器給出警告紊婉,所以打印結(jié)果為(null)。
所以辑舷,針對(duì)剛才的引用循環(huán)問(wèn)題喻犁,只需要將Test類的屬性objc設(shè)置weak修飾符,那么就能解決何缓。
@interface Test : NSObject
@property (weak, nonatomic) id objc;
@end
{
Test *test1 = [Test new]; /* 對(duì)象a */
/* test1有一個(gè)強(qiáng)引用到對(duì)象a */
Test *test2 = [Test new]; /* 對(duì)象b */
/* test2有一個(gè)強(qiáng)引用到對(duì)象b */
test1.objc = test2; /* 對(duì)象a的成員變量objc不持有對(duì)象b */
test2.objc = test1; /* 對(duì)象b的成員變量objc不持有對(duì)象a */
}
/* 當(dāng)變量test1超過(guò)它作用域時(shí)肢础,它指向a對(duì)象會(huì)自動(dòng)release
* 當(dāng)變量test2超過(guò)它作用域時(shí),它指向b對(duì)象會(huì)自動(dòng)release
*/
__unsafe_unretained ownership qualifier
__unsafe_unretained ownership qualifier碌廓,正如名字所示传轰,它是不安全的。它跟__weak相似谷婆,被它修飾的變量都不持有對(duì)象的所有權(quán)慨蛙,但當(dāng)變量指向的對(duì)象的RC為0時(shí)辽聊,變量并不設(shè)置為nil,而是繼續(xù)保存對(duì)象的地址期贫;這樣的話跟匆,對(duì)象有可能已經(jīng)釋放,但繼續(xù)訪問(wèn)通砍,就會(huì)造成非法訪問(wèn)(Invalid Access)贾铝。例子如下:
__unsafe_unretained id obj0 = nil;
{
id obj1 = [[NSObject alloc] init]; // 對(duì)象A
/* 由于obj1是強(qiáng)引用,所以obj1持有對(duì)象A的所有權(quán)埠帕,對(duì)象A的RC=1 */
obj0 = obj1;
/* 由于obj0是__unsafe_unretained垢揩,它不持有對(duì)象A的所有權(quán),但能夠引用它敛瓷,對(duì)象A的RC=1 */
NSLog(@"A: %@", obj0);
}
/* 當(dāng)obj1超過(guò)它的作用域時(shí)叁巨,它指向的對(duì)象A將會(huì)自動(dòng)釋放 */
NSLog(@"B: %@", obj0);
/* 由于obj0是__unsafe_unretained,當(dāng)它指向的對(duì)象RC=0時(shí)呐籽,它會(huì)繼續(xù)保存對(duì)象的地址锋勺,所以兩個(gè)地址相同 */
打印結(jié)果是內(nèi)存地址相同:
如果將__unsafe_unretained改為weak的話,兩個(gè)打印結(jié)果將不同
__weak id obj0 = nil;
{
id obj1 = [[NSObject alloc] init]; // 對(duì)象A
/* 由于obj1是強(qiáng)引用狡蝶,所以obj1持有對(duì)象A的所有權(quán)庶橱,對(duì)象A的RC=1 */
obj0 = obj1;
/* 由于obj0是__unsafe_unretained,它不持有對(duì)象A的所有權(quán)贪惹,但能夠引用它苏章,對(duì)象A的RC=1 */
NSLog(@"A: %@", obj0);
}
/* 當(dāng)obj1超過(guò)它的作用域時(shí),它指向的對(duì)象A將會(huì)自動(dòng)釋放 */
NSLog(@"B: %@", obj0);
/* 由于obj0是__weak奏瞬, 當(dāng)它指向的對(duì)象RC=0時(shí)枫绅,它會(huì)自動(dòng)設(shè)置為nil,所以兩個(gè)打印結(jié)果將不同*/
__autoreleasing ownership qualifier
引入ARC之后硼端,讓我們看看autorelease pool有哪些變化并淋。沒(méi)有ARC之前的寫法如下:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// put object into pool
id obj = [[NSObject alloc] init];
[obj autorelease];
[pool drain];
/* 超過(guò)autorelease pool作用域范圍時(shí),obj會(huì)自動(dòng)調(diào)用release方法 */
引入ARC之后珍昨,寫法比之前更加簡(jiǎn)潔:
@autoreleasepool {
id __autoreleasing obj = [[NSObject alloc] init];
}
相比之前的創(chuàng)建县耽、使用和釋放NSAutoreleasePool對(duì)象,現(xiàn)在你只需要將代碼放在@autoreleasepool塊即可镣典。你也不需要調(diào)用autorelease方法了兔毙,只需要用__autoreleasing修飾變量即可。
引用Pro Multithreading and Memory Management for iOS and OS X的圖
但是我們很少或基本上不使用autorelease pool骆撇。當(dāng)我們使用XCode創(chuàng)建工程后瞒御,有一個(gè)app的入口文件main.m使用了它:
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
roperty(屬性)
有了ARC之后,新的property modifier也被引入到Objective-C類的property神郊,例如:
@property (strong, nonatomic) NSString *text;
下面有張表來(lái)展示property modifier與ownership qualifier的對(duì)應(yīng)關(guān)系
總結(jié)
要想掌握iOS/OS X的內(nèi)存管理肴裙,首先要深入理解引用計(jì)數(shù)(Reference Count)這個(gè)概念以及內(nèi)存管理的規(guī)則趾唱;在沒(méi)引入ARC之前,我們都是通過(guò)retain和release方法來(lái)手動(dòng)管理內(nèi)存蜻懦,但引入ARC之后甜癞,我們可以借助編譯器來(lái)幫忙自動(dòng)調(diào)用retain和release方法來(lái)簡(jiǎn)化內(nèi)存管理和減低出錯(cuò)的可能性。雖然__strong修飾符能夠執(zhí)行大多數(shù)內(nèi)存管理宛乃,但它不能解決引用循環(huán)(Reference Cycle)問(wèn)題悠咱,于是又引入另一個(gè)修飾符__weak。被__strong修飾的變量都持有對(duì)象的所有權(quán)征炼,而被__weak修飾的變量并不持有對(duì)象所有權(quán)析既。下篇我們介紹使用工具如何解決常見(jiàn)內(nèi)存問(wèn)題:懸掛指針和內(nèi)存泄露。
軟件運(yùn)行時(shí)會(huì)分配和使用設(shè)備的內(nèi)存資源谆奥,因此眼坏,在軟件開(kāi)發(fā)的過(guò)程中,需要進(jìn)行內(nèi)存管理酸些,以保證高效宰译、快速的分配內(nèi)存,并且在適當(dāng)?shù)臅r(shí)候釋放和回收內(nèi)存資源魄懂。
一沿侈、Objective-C內(nèi)存管理的對(duì)象
IOS開(kāi)發(fā)中,內(nèi)存中的對(duì)象主要有兩類市栗,一類是值類型缀拭,比如int、float肃廓、struct等基本數(shù)據(jù)類型智厌,另一類是引用類型,也就是繼承自NSObject類的所有的OC對(duì)象盲赊。前一種值類型不需要我們管理,后一種引用類型是需要我們管理內(nèi)存的敷扫,一旦管理不好哀蘑,就會(huì)產(chǎn)生非常糟糕的后果。
為什么值類型不需要管理葵第,而引用類型需要管理呢绘迁?那是因?yàn)樗麄兎峙鋬?nèi)存方式不一樣。
值類型會(huì)被放入棧中卒密,他們依次緊密排列缀台,在內(nèi)存中占有一塊連續(xù)的內(nèi)存空間,遵循先進(jìn)后出的原則哮奇。引用類型會(huì)被放到堆中膛腐,當(dāng)給對(duì)象分配內(nèi)存空間時(shí)睛约,會(huì)隨機(jī)的從內(nèi)存當(dāng)中開(kāi)辟空間,對(duì)象與對(duì)象之間可能會(huì)留有不確定大小的空白空間哲身,因此會(huì)產(chǎn)生很多內(nèi)存碎片辩涝,需要我們管理。
棧內(nèi)存與堆內(nèi)存從性能上比較勘天,棧內(nèi)存要優(yōu)于堆內(nèi)存怔揩,這是因?yàn)闂W裱冗M(jìn)后出的原則,因此當(dāng)數(shù)據(jù)量過(guò)大時(shí)脯丝,存入棧會(huì)明顯的降低性能商膊。因此,我們會(huì)把大量的數(shù)據(jù)存入堆中宠进,然后棧中存放堆的地址晕拆,當(dāng)需要調(diào)用數(shù)據(jù)時(shí),就可以快速的通過(guò)棧內(nèi)的地址找到堆中的數(shù)據(jù)砰苍。
值類型和引用類型之間是可以相互轉(zhuǎn)化的潦匈,把值類型轉(zhuǎn)化為引用類型的過(guò)程叫做裝箱,比如把int包裝為NSNumber赚导,這個(gè)過(guò)程會(huì)增加程序的運(yùn)行時(shí)間茬缩,降低性能。而把引用類型轉(zhuǎn)為值類型的過(guò)程叫做拆箱吼旧,比如把NSNumer轉(zhuǎn)為float凰锡,在拆箱的過(guò)程中,我們一定要注意數(shù)據(jù)原有的類型圈暗,如果類型錯(cuò)誤掂为,可能導(dǎo)致拆箱失敗,因此會(huì)存在安全性的問(wèn)題员串。手動(dòng)的拆箱和裝箱勇哗,都會(huì)增加程序的運(yùn)行時(shí)間,降低代碼可讀性寸齐,影響性能欲诺。
在IOS開(kāi)發(fā)過(guò)程中,棧內(nèi)存中的值類型系統(tǒng)會(huì)自動(dòng)管理渺鹦,堆內(nèi)存中的引用類型是需要我們管理的扰法。每個(gè)OC對(duì)象內(nèi)部都專門有四個(gè)字節(jié)來(lái)存儲(chǔ)引用計(jì)數(shù)器,它是一個(gè)整數(shù)毅厚,表示對(duì)象被引用的次數(shù)塞颁,通過(guò)它可以判斷對(duì)象是否被回收,如果引用計(jì)數(shù)為0,對(duì)象回收祠锣,不為0不回收酷窥。當(dāng)對(duì)象執(zhí)行alloc、new或者retain時(shí)锤岸,引用計(jì)數(shù)加1竖幔,release時(shí),引用計(jì)數(shù)減1是偷。
二拳氢、Objective-C管理內(nèi)存的方式
Objective-c中提供了兩種內(nèi)存管理機(jī)制MRC(Mannul Reference Counting)和ARC(Automatic Reference Counting),分別提供對(duì)內(nèi)存的手動(dòng)和自動(dòng)管理蛋铆,來(lái)滿足不同的需求馋评。
1.MRC(人工引用計(jì)數(shù)),手動(dòng)管理內(nèi)存刺啦。
MRC模式下留特,所有的對(duì)象都需要手動(dòng)的添加retain、release代碼來(lái)管理內(nèi)存玛瘸。使用MRC蜕青,需要遵守誰(shuí)創(chuàng)建,誰(shuí)回收的原則糊渊。也就是誰(shuí)alloc右核,誰(shuí)release;誰(shuí)retain渺绒,誰(shuí)release贺喝。
當(dāng)引用計(jì)數(shù)為0的時(shí)候,必須回收宗兼,引用計(jì)數(shù)不為0躏鱼,不能回收,如果引用計(jì)數(shù)為0殷绍,但是沒(méi)有回收染苛,會(huì)造成內(nèi)存泄露。如果引用計(jì)數(shù)為0主到,繼續(xù)釋放殖侵,會(huì)造成野指針。為了避免出現(xiàn)野指針镰烧,我們?cè)卺尫诺臅r(shí)候,會(huì)先讓指針=nil楞陷。
2.ARC(自動(dòng)引用計(jì)數(shù))怔鳖,自動(dòng)管理內(nèi)存。
ARC是IOS5推出的新功能固蛾,通過(guò)ARC结执,可以自動(dòng)的管理內(nèi)存度陆。在ARC模式下,只要沒(méi)有強(qiáng)指針(強(qiáng)引用)指向?qū)ο笙揍#瑢?duì)象就會(huì)被釋放懂傀。在ARC模式下,不允許使用retain蜡感、release蹬蚁、retainCount等方法。并且郑兴,如果使用dealloc方法時(shí)犀斋,不允許調(diào)用[super dealloc]方法。
ARC模式下的property變量修飾詞為strong情连、weak叽粹,相當(dāng)于MRC模式下的retain、assign却舀。strong :代替retain虫几,缺省關(guān)鍵詞,代表強(qiáng)引用挽拔。weak:代替assign辆脸,聲明了一個(gè)可以自動(dòng)設(shè)置nil的弱引用,但是比assign多一個(gè)功能篱昔,指針指向的地址被釋放之后每强,指針本身也會(huì)自動(dòng)被釋放。
三州刽、與內(nèi)存有關(guān)的修飾符
strong :強(qiáng)引用空执,ARC中使用,與MRC中retain類似穗椅,使用之后辨绊,計(jì)數(shù)器+1。
weak :弱引用 匹表,ARC中使用门坷,如果只想的對(duì)象被釋放了,其指向nil袍镀,可以有效的避免野指針默蚌,其引用計(jì)數(shù)為1。
readwrite : 可讀可寫特性苇羡,需要生成getter方法和setter方法時(shí)使用绸吸。
readonly : 只讀特性,只會(huì)生成getter方法 不會(huì)生成setter方法,不希望屬性在類外改變锦茁。
assign :賦值特性攘轩,不涉及引用計(jì)數(shù),弱引用码俩,setter方法將傳入?yún)?shù)賦值給實(shí)例變量度帮,僅設(shè)置變量時(shí)使用。
retain :表示持有特性稿存,setter方法將傳入?yún)?shù)先保留笨篷,再賦值,傳入?yún)?shù)的retaincount會(huì)+1挠铲。
copy :表示拷貝特性冕屯,setter方法將傳入對(duì)象復(fù)制一份,需要完全一份新的變量時(shí)拂苹。
nonatomic :非原子操作安聘,不加同步,多線程訪問(wèn)可提高性能瓢棒,但是線程不安全的浴韭。決定編譯器生成的setter getter是否是原子操作。
atomic :原子操作脯宿,同步的念颈,表示多線程安全,與nonatomic相反连霉。
四榴芳、MRC與ARC混編
MRC與ARC理論上是不能兼容的,也就是你如果創(chuàng)建的項(xiàng)目是ARC模式的跺撼,在你的代碼中是不能使用release窟感,否則會(huì)出現(xiàn)內(nèi)存問(wèn)題。現(xiàn)在大部分程序都會(huì)選擇ARC的方式歉井,但是很多第三方的框架是MRC模式柿祈,如果想把這些第三方的文件加到自己項(xiàng)目中,需要進(jìn)行標(biāo)識(shí)哩至,否則編譯的時(shí)候會(huì)出現(xiàn)錯(cuò)誤躏嚎。
在ARC的項(xiàng)目中,對(duì)MRC的文件可以添加編譯選項(xiàng)-fno-objc-arc的標(biāo)識(shí)菩貌;在MRC的項(xiàng)目中卢佣,對(duì)ARC的文件可以添加編譯選項(xiàng) -fobjc-arc的標(biāo)識(shí)。
把MRC文件轉(zhuǎn)為ARC箭阶,實(shí)際上是去掉文件中的retain珠漂、release晚缩,