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