昨天立了flag,今天就來(lái)開(kāi)始第一篇文章吧。
property的關(guān)鍵字是我們平常寫代碼隨時(shí)都會(huì)用到的,只要聲明一個(gè)屬性,就會(huì)用到這些關(guān)鍵字,先從最簡(jiǎn)單的講起吧。
一、如何使用
property的關(guān)鍵字分三類:
- 一類是表示原子性(也就是線程安全)的,有atomic和nonatomic,默認(rèn)是atomic,acomic也就是線程安全,但是我們一般都用的nonatomic,因?yàn)閍tomic的線程安全開(kāi)銷太大,影響性能,即使需要保證線程安全,我們也可以通過(guò)自己的代碼控制,而不用atomic。
- 一類是表示引用計(jì)數(shù)的,有assign(iOS5以前用unsafe_unretained),strong,weak,copy。
assign: assign用于非指針變量,一般用于基礎(chǔ)類型和C數(shù)據(jù)類型,這些類型不是對(duì)象,統(tǒng)一由系統(tǒng)棧進(jìn)行內(nèi)存管理。
weak:對(duì)對(duì)象的弱引用,不增加對(duì)象的引用計(jì)數(shù),也不持有對(duì)象,當(dāng)對(duì)象消失后指針自動(dòng)指向nil,所以這里也就防止了野指針的存在。
strong:對(duì)對(duì)象的強(qiáng)引用,會(huì)增加對(duì)象的引用計(jì)數(shù),如果指向了一個(gè)空對(duì)象,會(huì)造成野指針,平常我們用得最多的應(yīng)該也是strong了。
copy:建立一個(gè)引用計(jì)數(shù)為1的新對(duì)象,賦值時(shí)對(duì)傳入值進(jìn)行一份拷貝,所以使用copy關(guān)鍵字的時(shí)候,你將一個(gè)對(duì)象復(fù)制給該屬性,該屬性并不會(huì)持有那個(gè)對(duì)象,而是會(huì)創(chuàng)建一個(gè)新對(duì)象,并將那個(gè)對(duì)象的值拷貝給它。而使用copy關(guān)鍵字的對(duì)象必須要實(shí)現(xiàn)NSCopying協(xié)議。
unsafe_unretained:跟 weak 類似,聲明一個(gè)弱引用,但是當(dāng)引用計(jì)數(shù)為 0 時(shí),變量不會(huì)自動(dòng)設(shè)置為 nil,現(xiàn)在基本都用weak了。 - 一類是表示讀寫權(quán)限的,默認(rèn)是readwrite(可讀可寫),還有就是readonly,當(dāng)你希望暴露出來(lái)的屬性不能被外界修改時(shí)就需要申明為readonly。
二、關(guān)鍵字與內(nèi)存管理
這里重點(diǎn)講一下與內(nèi)存管理相關(guān)的這幾個(gè)關(guān)鍵字。
直接上代碼吧
測(cè)試
@property (nonatomic,strong) Person *strongPerson;
@property (nonatomic,weak) Person *weakPerson;
試驗(yàn)代碼
self.strongPerson = [Person new];
self.weakPerson = self.strongPerson;
self.strongPerson = nil; NSLog(@"strongStr=%@,weakStr=%@",self.strongPerson,self.weakPerson);
輸出結(jié)果為:
strongStr=(null),weakStr=(null)
這里就足以說(shuō)明weak修飾的屬性并不會(huì)使引用計(jì)數(shù)增加
稍微修改代碼,把weakPerson設(shè)置為nil
self.strongPerson = [Person new];
self.weakPerson = self.strongPerson;
self.weakPerson = nil;
NSLog(@"strongStr=%@,weakStr=%@",self.strongPerson,self.weakPerson);
輸出結(jié)果如下:
strongStr=<Person: 0x600000007d50>,weakStr=(null)
說(shuō)明weak修飾的屬性只是對(duì)對(duì)象的弱引用,并不會(huì)真正的持有該對(duì)象。
再次修改代碼
Person *p = [Person new];
self.strongPerson = p;
self.weakPerson = self.strongPerson;
p = nil;
NSLog(@"strongStr=%@,weakStr=%@",self.strongPerson,self.weakPerson);
輸出結(jié)果為:
strongStr=<Person: 0x600000200b50>,weakStr=<Person: 0x600000200b50>
這里不用多說(shuō),因?yàn)閟trong屬性會(huì)強(qiáng)引用該對(duì)象并使該對(duì)象的引用計(jì)數(shù)+1,所以即使把p設(shè)置為nil,該對(duì)象也并沒(méi)有釋放,要想釋放該對(duì)象,還得把strongStr設(shè)置為nil。
self.strongPerson = nil;
這樣輸出結(jié)果就是 strongStr=(null),weakStr=(null)了。
再來(lái)看看copy關(guān)鍵字
為了方便試驗(yàn),我們直接在ViewController里面加個(gè)屬性。
@property (nonatomic, copy) NSObject *c;
NSObject *a = [[NSObject alloc]init];
self.c = a;
a = nil;
NSLog(@"%@",self.c);
毫無(wú)疑問(wèn),輸出結(jié)果不為nil。
<NSObject: 0x600000010d90>
在這里要重點(diǎn)說(shuō)一下,使用NSMutableArray,NSMutableDictionary等可變集合對(duì)象的時(shí)候千萬(wàn)不要用copy,這里用copy 99%會(huì)出錯(cuò),因?yàn)楫?dāng)你給該屬性賦值時(shí)它會(huì)自動(dòng)調(diào)用對(duì)象的copy方法,從而將可變集合轉(zhuǎn)換成不可變集合,把一個(gè)不可變集合賦值給一個(gè)可變集合,就會(huì)造成錯(cuò)誤。
感覺(jué)寫得有些啰嗦,我覺(jué)得主要是給新人看吧,畢竟我自己當(dāng)初一直對(duì)這些關(guān)鍵字也是懵懵懂懂的,如果看了我這篇文章還是不能理解,那應(yīng)該是完全不了解內(nèi)存管理方面的知識(shí),MRC、ARC應(yīng)該去了解一下,如果后面有需要,我可能會(huì)寫一篇相關(guān)的文章。
另外,還請(qǐng)大神門多多指教。。。。
更新
之前是用NSString來(lái)做的實(shí)驗(yàn),但是由于字符串的特殊性,所以有點(diǎn)容易誤導(dǎo)大家,現(xiàn)在已經(jīng)全部改成了普通類了。關(guān)于字符串類型,主要是蘋果在編譯期做了一些優(yōu)化,讓它的特性跟普通變量有點(diǎn)類似,在這里就不說(shuō)太多了,以免給大家造成困惑。