@property是OC中用到的,最重要的key words。
我們經常看到assign,retain,copy和strong,weak nonatomic等關鍵字出現在它之后。這個背后必然有各種陰謀,必須弄清,不然又是個坑的節奏。
非ARC環境
現在基本都用ARC了,不過一切都是有發展軌跡的,最新的技術也是從這個發展過來的。
assign屬性
assign做的事情其實就是拷貝了指針。讓這個屬性只是復制你所賦給它的值的指針。于是,它們就共同指向了同一個區域了。
當數據類型為int、float等原生類型時,可以使用assign,否則可能導致內存泄露。例如當使用malloc分配了一塊內存,并把它的地址賦值給了指針a,后來如果希望指針b也共享這塊內存,于是講a賦值給(assgin)b。這時就用到了assgin,此時a和b指向同一塊內存。但是現在問題出現了,當a不再需要這塊內存時,能都直接釋放呢?肯定是不能的,因為a并不知道b是否還在使用這塊內存,如果a釋放了,那么b在使用這塊內存的時候引起程序crash掉。
一般,assign對基礎數據類型 (例如NSInteger,CGFloat)和C數據類型(int, float, [double] 等簡單數據類型適用
retain屬性
retain屬性就是為了解決上述問題而提出的,使用了引用計數(reference counting),還是上面那個例子,我們給那塊內存設一個引用計數,當內存唄分配并且賦值給a時,引用計數是1.當把a賦值給b時引用計數增加到2.這時如果a不再使用這塊內存,它只需要把引用計數減1,表明自己不再擁有這塊內存。b不再使用這塊內存時也把引用計數減1.當引用計數變為0的時候,代表該內存不再被任何指針所引用,系統可以直接釋放掉。此時系統自動調用dealloc函數,內存被回收。
所以因為和引用計數相關,所以必須是支持引用計數的對象才行。一般是NS系的復雜對象玩意才能比較好的用這個。
copy屬性
copy就是新創建一塊內存區域,復制變量的內容進來。只是保證了變量的內容相同,內存區域并不同。
這里還涉及 深拷貝和 淺拷貝 相關的知識。
ARC環境
ARC環境下,strong代替retain.weak代替assign
weak(類似assign)
在ARC環境下,對象的銷毀不會受到weak指針的指向而不被銷毀。
同時,所有指向銷毀對象的weak指針都將被置為nil。這個特性很有用,相信很多開發者都被指針指向已釋放的對象所造成的EXC_BAD_ACCESS困擾過,使用ARC以后,不論是strong還是weak類型的指針,都不會再指向一個已經銷毀的對象,從根本上解決了意外釋放導致的crash。
strong(類似retain)
在ARC環境下,只要某一對象被一個strong指針指向,該對象就不會被銷毀。如果對象沒有被任何strong指針指向,那么就會被銷毀。在默認情況下,所有的實例變量和局部變量都是strong類型的。可以說strong類型的指針在行為上跟非ARC下得retain是比較相似的
weak和strong的區別
- weak 和 strong 屬性只有在你打開ARC時才會被要求使用,這時你是不能使用retain release autorelease 操作的,因為ARC會自動為你做好這些操作,但是你需要在對象屬性上使用weak 和strong,其中strong就相當于retain屬性,而weak相當于assign。
- 只有一種情況你需要使用weak(默認是strong),就是為了避免retain cycles(就是父類中含有子類{父類retain了子類},子類中又調用了父類{子類又retain了父類},這樣都無法release)
- 聲明為weak的指針,指針指向的地址一旦被釋放,這些指針都將被賦值為nil。這樣的好處能有效的防止野指針。
其他屬性
讀寫
- readonly:屬性是只讀的,默認的標記是讀寫,如果你指定了只讀,在@implementation中只需要一個讀取器。或者如果你使用@synthesize關鍵字,也是有讀取器方法被解析(只生成getter,setter不會被生成)
- readwrite:說明屬性會被當成讀寫的,這也是默認屬性。設置器和讀取器都需要在@implementation中實現。如果使用@synthesize關鍵字,讀取器和設置器都會被解析(getter和setter 都會被生成)
原子屬性
- nonatomic:非原子性訪問,對屬性賦值的時候不加鎖,多線程并發訪問會提高性能。如果不加此屬性,則默認是兩個訪問方法都為原子型事務訪問;nonatomic是不能保證線程安全的。但是nonatomic比atomic速度要快。這也是為什么property基本上都用nonatomic了
- atomic: 默認屬性。無atomic這個關鍵字,直接不加nonatomic就好。atomic是保證讀取變量是線程安全的,即它會保證每次getter和setter的操作都會正確的執行完畢,而不用擔心其它線程在你get的時候set,可以說保證了某種程度上的線程安全。 最后加上一句,僅僅靠atomic來保證線程安全是不可能的,要寫出線程安全的代碼,還是需要有同步和互斥機制。
@property的默認屬性
readwrite,atomic(即不寫nonatomic)
非ARC環境下, 默認為assign
在ARC環境下,默認為strong