Objective-C的屬性用于封裝對象之中的資料,其作用同類的資料成員類似,但是所起到的作用遠遠大于普通的資料成員。聲明屬性使用@property關鍵字,這樣就可以快速友善地為執行個體變量建立存取器,并可以通過點文法使用使用存取器。擷取屬性的變量值使用getter方法,設定屬性的變量值使用setter方法。
使用屬性的例子如下:
@property等同于在頭檔案中聲明了set和get方法,同時也自動在實作檔案中使用synthesize實作了set和get方法。相對于自己手動聲明資料和方法成員,使用屬性可以大幅簡化代碼。
在聲明屬性的時候,還需要制定一些關鍵字對屬性進行修飾,如nonatomatic、copy等。一般用來修飾屬性的特性關鍵字有三類:原子性、存取器控制和記憶體管理。
atomic:使用該特性修飾的屬性是線程互斥的,即最多隻能有一個線程同時通路。該屬性是預設的,隻有在嚴格要求線程安全的場合下會使用。
nonatomic:使用該特性修飾的屬性時線程非安全的,可以同時被多個線程通路。使用nonatomic的屬性效率相對較高,在大多數場合使用的是這個特性。
主要用于控制屬性的set和get方法。
readwrite:預設屬性,表示該屬性同時支援讀操作和寫操作,同時具有setter和getter。
readonly:表示該屬性隻讀,隻有getter沒有setter。
另外,還可以自定義setter和getter的函數名,如:
記憶體管理特性表明了該屬性與保有它的對象之間的關系:
assign:預設屬性,用于值關系。通常int、float等數值類型極其封裝如NSInteger等屬性,以及代理對象通常采用assign特性。
retain:父對象對屬性對象擁有所有權,父對象建立後,屬性對象的引用計數加1。隻要父對象的引用存在,那麼屬性對象就不會被釋放。對于大部分“類”類型的屬性,應采用retain特性。
copy:與retain類似,父對象存在對屬性對象的強引用,但是會在父對象建立時為屬性對象建立一份拷貝副本,父對象引用的是這一個副本。使用最多的是NSString類型的屬性。
在iOS加入了ARC後,屬性的記憶體管理特性新增添了strong和weak兩個:
strong:與retain相同,即父對象對屬性對象強引用,屬性對象的引用計數+1,屬性對象不會在父對象生命周期結束之前被釋放。
weak:類似于assign,即父對象對屬性對象弱引用,屬性對象的引用計數不增加,父對象也不能幹涉屬性對象生命周期,當屬性對象在其他地方被釋放之後,父對象的這個屬性被設定為nil。
unsafe_unretain:該屬性類似于assign,說明父對象不對屬性對象存在強引用,但是與weak不同的是當屬性對象被釋放後,父對象的屬性不會被設定為nil。
這兩種通路方式有幾個差別:
直接通路類成員的速度較快,因為省略了Objective-C的“方法派發”,編譯出來的代碼會直接通路執行個體成員的記憶體。
直接通路類成員,将繞過其setter和getter方法,那麼屬性聲明時規定的特性将失效。
直接通路類成員,不會觸及KVO。
在對象外部通路對象的屬性成員,總應該使用屬性;在對象内部,應該盡量直接通路執行個體成員。另外,還需要遵循以下規定:
對象内部讀取資料時直接通路,寫入資料時通過屬性來寫入;
在init和dealloc方法中,始終直接通路執行個體變量;
在進行了惰性初始化時,通過屬性來讀取資料。