iOS屬性關(guān)鍵字

iOS屬性關(guān)鍵字

引言

學(xué)習(xí) iOS 開發(fā)的人棺滞,大多都繞不開屬性關(guān)鍵字—— assign纷铣,weak将饺,unsafe_unretained贡避,strong,retain 予弧,copy刮吧,readonly,readwrite , nonatomic掖蛤,natomic及 __weak杀捻,__block ,@synthesize 和 @dynamic 等蚓庭;大概很多人都對這個致讥,只要最后程序不崩潰,能正常運行彪置,不會過多去探究拄踪;但實際上,如果可以正確的使用這些屬性拳魁,是可以大大提高代碼質(zhì)量惶桐,同時對代碼結(jié)構(gòu)的理解上也能更上一層樓。


原理

首先要知道倆點潘懊,iOS 代碼實現(xiàn)并不僅僅是靠上層 OC 實現(xiàn)的姚糊,實現(xiàn)的基礎(chǔ)是來源于 apple 的 SDK ,基于這個 SDK 提供的基礎(chǔ)庫授舟,我們才能開發(fā)出 apple 風(fēng)格的 APP救恨;還有一點就是 xcode 代碼提示 、 錯誤释树、警告 等提示 肠槽,其本身就是一種協(xié)議約定擎淤。

這些關(guān)鍵字是怎么來的呢?如果你能明白這個問題秸仙,你就明白了其原理嘴拢。

對一個屬性來說,無非倆個操作寂纪,讀和取席吴,對應(yīng)的就是 get 和 set 方法;通俗一點講捞蛋,這些關(guān)鍵字是底層約定的一些標(biāo)簽孝冒,當(dāng)你上層對聲明的屬性加上這些關(guān)鍵字時,底層會根據(jù)不同的標(biāo)簽拟杉,在 get 和 set 方法中庄涡,執(zhí)行不同的代碼。

舉個例子:

  聲明: ` @property (nonatomic,strong) NSString  *name;`
    @synthesize  name = _name;
            // set 方法
            - (void)setName:(NSString *)name
            {
                _name = name;
            }
            // get 方法
            - (NSString *)name
            {
                return  _name;
            }
            
            - (void)getName:(NSString **)buffer range:(NSRange)inRange
            {
                *buffer = _name;
            }
            

這上面的代碼其實是沒有意義的捣域,因為底層 SDK 生成的方法中啼染,已經(jīng)包含了這幾個方法 , 這里只是展示一下聲明后得到的方法 焕梅,另外想一想為什么加了這些屬性后代碼提示中就能出這些方法迹鹅。nonatomic、strong 其實就是標(biāo)簽 贞言,根據(jù)這些標(biāo)簽斜棚,生成不同的 set 和 get 執(zhí)行策略。下面就來具體說一說该窗,不同關(guān)鍵字對應(yīng)的策略是什么弟蚀。


nonatomic、atomiac

簡單從詞意上理解酗失,nonatomic 非原子的义钉, atomiac 原子的 。屬性默認(rèn)是 atomiac 规肴, 也就是原子性的捶闸。

這對 CP,是用于區(qū)分在多線程下拖刃,屬性讀取策略删壮。
atomiac: 不受其他線程的影響,在 get 一個屬性時兑牡,立馬給這個屬性在當(dāng)前線程加一個鎖央碟,只有當(dāng) get 完成后,才會解鎖均函,才會同步其他線程的 set 值亿虽。
nonatomic: 受線程影響菱涤,在 get 一個屬性時, 不管是否有其他線程執(zhí)行 set 方法经柴, 只返回 get 結(jié)束時的 set 值狸窘。
從這也可以看出,nonatomic 聲明的屬性坯认,執(zhí)行速率上是要更快一點的 ; 其實 atomiac 這個屬性在上層代碼中,其實非常不常用氓涣,因為很少會遇到存在同時牛哺,多個線程對一個屬性 set 。


readwrite劳吠、readonly

詞意上理解引润,readwrite 讀寫,readonly 只讀痒玩。 屬性默認(rèn)是 readwrite 淳附, 支持讀寫。

這對 CP蠢古,是對set 和 get 方法的一個總開關(guān)奴曙。
readwirte: 屬性同時具有 set 和 get 方法。
readonly: 屬性只具有 get 方法草讶。
這倆關(guān)鍵字洽糟,就是和其詞意一樣 ,若只想類內(nèi)部 set , 就聲明 readonly堕战。


strong坤溃、retain、weak嘱丢、assign薪介、copy、unsafe_unretained

這個幾個從詞意上就很難理解了越驻。 retain 汁政、assign 是 MRC 時的關(guān)鍵字,到 ARC 時伐谈,換成了 strong 和 weak 烂完。 屬性默認(rèn)是 MRC -- assign ;ARC -- object 是 strong,基本數(shù)據(jù)類型還是 assign 诵棵。 實際上 weak 和 assign 還是有一些不同的抠蚣,strong 和 retain 幾乎沒什么區(qū)別,不過建議還是能用 retain 的地方盡量用 strong 履澳, 后面也不講 retain 嘶窄。 講到這幾個關(guān)鍵字怀跛,就必須說到引用計數(shù)(retainCount)生命周期

由于 strong 是不能修飾基礎(chǔ)數(shù)據(jù)類型的柄冲,我以為 ARC 中應(yīng)該默認(rèn)屬性關(guān)鍵字應(yīng)該不是 strong吻谋,但實際上不是,下面是 iOS Document 提到

Use Strong and Weak Declarations to Manage Ownership
By default, object properties declared like this:
@property id delegate;
use strong references for their synthesized instance variables. To declare a weak reference, add an attribute to the property, like this:
@property (weak) id delegate;
Note: The opposite to weak is strong. There’s no need to specify the **strong** attribute explicitly, because it is the **default**.

后面求證后现横,發(fā)現(xiàn)確實也是這樣漓拾,所以猜測 ARC 中 對象默認(rèn)是 strong,基本數(shù)據(jù)類型默認(rèn)還是 assign戒祠。

對整個 APP 來說是內(nèi)存管理機(jī)制骇两,對單個屬性來說就是生命周期 ,而引用計數(shù)就是核心姜盈。
這里簡單說明一下: iOS 有個內(nèi)存池的概念低千,所有的屬性創(chuàng)建的時候都會被內(nèi)存池關(guān)注,這個時候 retainCount = 1 馏颂,中間對這個屬性進(jìn)行操作時示血, retainCount 可能會增加 或者 減少 ,但當(dāng) retainCount = 0 時救拉, 內(nèi)存池檢測到后难审,就會釋放這個屬性對應(yīng)的內(nèi)存空間 。


strong近上、weak剔宪、assign、unsafe_unretained

先從字面上理解一下壹无, strong 強(qiáng)的葱绒,weak 弱的、虛的斗锭, assign 分配 地淀,unsafe_unretained 不安全且不 retain 的。

  • strong 和 weak

strong 是每對這個屬性引用一次岖是,retainCount 就會+1帮毁,只能修飾 NSObject 對象,不能修飾基本數(shù)據(jù)類型豺撑。是 id 和 對象 的默認(rèn)修飾符烈疚。
weak 對屬性引用時,retainCount 不變聪轿,只能修飾 NSObject 對象爷肝,不能修飾基本數(shù)據(jù)類型。 主要用于避免循環(huán)引用。

  • assign

這個關(guān)鍵字灯抛,是默認(rèn)關(guān)鍵字金赦,可以修飾基本數(shù)據(jù)類型和 NSObject 對象。
對這個關(guān)鍵字聲明的屬性操作時对嚼,retainCount 是一直不變的夹抗,一直為 1,只有主動調(diào)用 release 時 纵竖,才會釋放漠烧。
但是為什么我們不會用assign去聲明對象呢?
這是因為 assign 修飾的對象(一般編譯的時候會產(chǎn)生警告:Assigning retained object to unsafe property; object will be released after assignment)在釋放之后磨确,指針的地址還是存在的沽甥,也就是說指針并沒有被置為nil,造成野指針乏奥。對象分配在堆上的某塊內(nèi)存,如果在后續(xù)的內(nèi)存分配中亥曹,剛好分到了這塊地址邓了,程序就會 crash。
為什么可以用assign修飾基本數(shù)據(jù)類型媳瞪?
因為基礎(chǔ)數(shù)據(jù)類型是分配在棧上骗炉,棧的內(nèi)存會由系統(tǒng)自己自動處理回收,不會造成野指針蛇受。

  • unsafe_unretained

這個關(guān)鍵字和 week 非常相似句葵, 也是可以同時修飾基本數(shù)據(jù)類型和 NSObject 對象 ,其實它本身是 week 的前身 , 在 iOS5 之后兢仰,基本都用 week 代替了 unsafe_unretained 乍丈。 但它們之間還是稍微有點區(qū)別的,并不是完全一樣把将,對上層代碼來說轻专,能用 unsafe_unretained 的地方,都可以用 week 代替察蹲。同時要注意一點请垛,這個修飾符修飾的變量不屬于編譯器的內(nèi)存管理對象。

  • copy
    復(fù)制的意思洽议,意思非常明確宗收,但用起來是最要注意的。
    這個關(guān)鍵字類似 strong 亚兄,只能修飾 NSObject 對象混稽,不能修飾基本數(shù)據(jù)類型。和 strong 不一樣的地方是, copy 后的對象 荚坞,指針地址是和之前不一樣的挑宠,也就是說重新分配了一塊內(nèi)存,也就是所謂的深拷貝颓影。這個關(guān)鍵字在用的時候各淀,因為涉及到申請新的內(nèi)存空間,所以要少用诡挂,能用 strong 的地方都用 strong 碎浇,只有必須用 copy 的地方才用 copy 。
    另外要注意璃俗,copy 修飾可變類型的屬性時要小心奴璃,如NSMutableArray、NSMutableDictionary城豁、NSMutableString 苟穆,因為會容易造成 crash。

__weak唱星、__block雳旅、__strong、__copy 间聊、__autorelease 等

類似這樣的關(guān)鍵字攒盈,其實和沒有‘__’還是一樣,只是在 .m 中聲明就是這個樣子哎榴,另外提到 .m 文件中型豁,新生產(chǎn)的對象,其實默認(rèn)都有 __strong 尚蝌。


@synthesize 和 @dynamic 分別有什么作用迎变?

  • @property 有兩個對應(yīng)的詞,一個是 @synthesize驼壶,一個是 @dynamic氏豌。如果 @synthesize 和 @dynamic 都沒寫,那么默認(rèn)的就是 @syntheszie var = _var;
  • @synthesize 的語義是如果你沒有手動實現(xiàn) setter 方法和 getter 方法热凹,那么編譯器會自動為你加上這兩個方法泵喘。
  • @dynamic 告訴編譯器:屬性的 setter 與 getter 方法由用戶自己實現(xiàn),不自動生成般妙。(當(dāng)然對于 readonly 的屬性只需提供 getter 即可)纪铺。假如一個屬性被聲明為 @dynamic var,然后你沒有提供 @setter 方法和 @getter 方法碟渺,編譯的時候沒問題鲜锚,但是當(dāng)程序運行到 instance.var = someVar,由于缺 setter 方法會導(dǎo)致程序崩潰;或者當(dāng)運行到 someVar = var 時芜繁,由于缺 getter 方法同樣會導(dǎo)致崩潰旺隙。編譯時沒問題,運行時才執(zhí)行相應(yīng)的方法骏令,這就是所謂的動態(tài)綁定蔬捷。

iOS9的幾個新關(guān)鍵字(nonnull、nullable榔袋、null_resettable周拐、__null_unspecified 、__kindof)

  • nonnull
    字面意思就能知道:不能為空(用來修飾屬性,或者方法的參數(shù),方法的返回值)
  • nullable
    表示可以為空
  • null_resettable
    get 不能返回空, set 可以為空(注意:如果使用null_resettable,必須重寫 get 方法或者 set 方法,處理傳遞的值為空的情況))
  • __null_unspecified
    不確定是否為空 (很操蛋凰兑。妥粟。。)
  • __kindof
    放在類型前面,表示修飾這個類型(__kindof MyCustomClass *)
    表示當(dāng)前類,也可以表示當(dāng)前類的子類

總結(jié)

對這些關(guān)鍵字的認(rèn)知是非常有必要的吏够,很好的使用這些關(guān)鍵字勾给,可以讓代碼優(yōu)美,另外也減少不必要的開銷锅知,提高APP運行效率锦秒。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市喉镰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌惭笑,老刑警劉巖侣姆,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異沉噩,居然都是意外死亡捺宗,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門川蒙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蚜厉,“玉大人,你說我怎么就攤上這事畜眨≈缗#” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵康聂,是天一觀的道長贰健。 經(jīng)常有香客問我,道長恬汁,這世上最難降的妖魔是什么伶椿? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上脊另,老公的妹妹穿的比我還像新娘导狡。我一直安慰自己,他們只是感情好偎痛,可當(dāng)我...
    茶點故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布旱捧。 她就那樣靜靜地躺著,像睡著了一般看彼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上靖榕,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天,我揣著相機(jī)與錄音茁计,去河邊找鬼。 笑死星压,一個胖子當(dāng)著我的面吹牛践剂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播娜膘,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼竣贪!你這毒婦竟也來了军洼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤演怎,失蹤者是張志新(化名)和其女友劉穎匕争,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體甘桑,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡歹叮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了艘蹋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片票灰。...
    茶點故事閱讀 40,664評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡宅荤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出冯键,到底是詐尸還是另有隱情庸汗,我是刑警寧澤,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布改化,位于F島的核電站,受9級特大地震影響陈肛,放射性物質(zhì)發(fā)生泄漏兄裂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一晰奖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧啃匿,春花似錦、人聲如沸立宜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至崖技,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間迎献,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工扒秸, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人伴奥。 一個月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓拾徙,卻偏偏與公主長得像洲炊,于是被迫代替她去往敵國和親尼啡。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容