編寫高質(zhì)量iOS與OS X代碼的52個(gè)有效方法(二)

對(duì)象、消息瓜晤、運(yùn)行時(shí)

理解“屬性”的概念

屬性的基礎(chǔ)用法就不多敘述了
屬性特質(zhì)

@property (nonatomic,readwrite,copy) NSString *name;

屬性擁有的特質(zhì)分為4類

1黍聂、原子性

atomic
設(shè)置成員變量的@property屬性時(shí),默認(rèn)為atomic瓮恭,提供多線程安全雄坪。
在多線程環(huán)境下,原子操作是必要的屯蹦,否則有可能引起錯(cuò)誤的結(jié)果维哈。加了atomic,setter函數(shù)會(huì)變成下面這樣:

{lock} 
  if (property != newValue) {                              
    [property release];                                       
    property = [newValue retain];                               
  }                      
{unlock}

nonatomic
禁止多線程颇玷,變量保護(hù)笨农,提高性能。 atomic是Objc使用的一種線程保護(hù)技術(shù)帖渠,基本上來講谒亦,是防止在寫未完成的時(shí)候被另外一個(gè)線程讀取,造成數(shù)據(jù)錯(cuò)誤空郊。而這種機(jī)制是耗費(fèi)系統(tǒng)資源的份招,所以在iPhone這種小型設(shè)備上,如果沒有使用多線程間的通訊編程狞甚,那么nonatomic是一個(gè)非常好的選擇锁摔。
指出訪問器不是原子操作,而默認(rèn)地哼审,訪問器是原子操作谐腰。這也就是說,在多線程環(huán)境下涩盾,解析的訪問器提供一個(gè)對(duì)屬性的安全訪問十气,從獲取器得到的返回值或者通過設(shè)置器設(shè)置的值可以一次完成,即便是別的線程也正在對(duì)其進(jìn)行訪問春霍。如果你不指定 nonatomic 砸西,在自己管理內(nèi)存的環(huán)境中,解析的訪問器保留并自動(dòng)釋放返回的值址儒,如果指定了 nonatomic 芹枷,那么訪問器只是簡單地返回這個(gè)值。
開發(fā)iOS程序時(shí)莲趣,應(yīng)該使用nonatomic屬性鸳慈,因?yàn)閍tomic屬性會(huì)嚴(yán)重影響性能。

2妖爷、讀/寫權(quán)限

readwrite會(huì)自動(dòng)生成getter/setter方法
readonly只有g(shù)etter方法

3蝶涩、內(nèi)存管理語義

assign “設(shè)置方法”只會(huì)執(zhí)行針對(duì)“純量類型”(CGFloat&&NSIntger等)的簡單賦值操作理朋。
strong 此特質(zhì)表明該屬性定義了一種“擁有關(guān)系”。賦值時(shí)會(huì)保留新值绿聘,并釋放舊值嗽上,然后再講新值設(shè)置上去
weak 此特質(zhì)表明該屬性定義了一種“非擁有關(guān)系”。賦值時(shí)既不保留新值熄攘,也不釋放舊值兽愤,同assign相似。然而屬性所指的對(duì)象銷毀時(shí)挪圾,屬性值也會(huì)被nil浅萧;
unsafe_unretained此特質(zhì)的語義和assign相同,但他適用于對(duì)象類型哲思,該特質(zhì)表達(dá)一種“非擁有關(guān)系”(“不保留”)洼畅,當(dāng)目標(biāo)對(duì)象遭到銷毀時(shí),屬性值不會(huì)被清空棚赔,與weak有區(qū)別帝簇。
copy所表達(dá)的所屬關(guān)系與strong相似。然而設(shè)置方法并不保留新值靠益,而是將其copy丧肴。當(dāng)屬性類型為NSString時(shí),經(jīng)常用此特質(zhì)來保護(hù)其封裝性胧后,因?yàn)閭鬟f給設(shè)置方法的新值有可能指向一個(gè)NSMutableString類的實(shí)例芋浮。這個(gè)類是NSString的子類,表示可修改字符串壳快,此時(shí)若是不拷貝字符串纸巷,那么設(shè)置完屬性之后,字符串的值可能會(huì)在對(duì)象不知情的情況下遭到更改眶痰。

weak比 assign多了一個(gè)功能就是當(dāng)屬性所指向的對(duì)象消失的時(shí)候(也就是內(nèi)存引用計(jì)數(shù)為0)會(huì)自動(dòng)賦值為 nil何暇,這樣再向 weak修飾的屬性發(fā)送消息就不會(huì)導(dǎo)致野指針操作crash。

weak如何自動(dòng)置nil凛驮?
runtime 對(duì)注冊(cè)的類, 會(huì)進(jìn)行布局条辟,對(duì)于 weak 對(duì)象會(huì)放入一個(gè) hash 表中黔夭。 用 weak 指向的對(duì)象內(nèi)存地址作為 key,當(dāng)此對(duì)象的引用計(jì)數(shù)為0的時(shí)候會(huì) dealloc羽嫡,假如 weak 指向的對(duì)象內(nèi)存地址是a本姥,那么就會(huì)以a為鍵, 在這個(gè) weak 表中搜索杭棵,找到所有以a為鍵的 weak 對(duì)象婚惫,從而設(shè)置為 nil氛赐。

用@property聲明的NSString(或NSArray,NSDictionary)經(jīng)常使用copy關(guān)鍵字先舷,為什么艰管?如果改用strong關(guān)鍵字,可能造成什么問題蒋川?

因?yàn)楦割愔羔樋梢灾赶蜃宇悓?duì)象,使用 copy 的目的是為了讓本對(duì)象的屬性不受外界影響,使用 copy 無論給我傳入是一個(gè)可變對(duì)象還是不可對(duì)象,我本身持有的就是一個(gè)不可變的副本.
如果我們使用是 strong ,那么這個(gè)屬性就有可能指向一個(gè)可變對(duì)象,如果這個(gè)可變對(duì)象在外部被修改了,那么會(huì)影響該屬性.

copy 此特質(zhì)所表達(dá)的所屬關(guān)系與 strong 類似牲芋。然而設(shè)置方法并不保留新值,而是將其“拷貝” (copy)捺球。 當(dāng)屬性類型為 NSString 時(shí)缸浦,經(jīng)常用此特質(zhì)來保護(hù)其封裝性,因?yàn)閭鬟f給設(shè)置方法的新值有可能指向一個(gè) NSMutableString 類的實(shí)例氮兵。這個(gè)類是 NSString 的子類裂逐,表示一種可修改其值的字符串,此時(shí)若是不拷貝字符串泣栈,那么設(shè)置完屬性之后卜高,字符串的值就可能會(huì)在對(duì)象不知情的情況下遭人更改。所以秩霍,這時(shí)就要拷貝一份“不可變” (immutable)的字符串篙悯,確保對(duì)象中的字符串值不會(huì)無意間變動(dòng)。只要實(shí)現(xiàn)屬性所用的對(duì)象是“可變的” (mutable)铃绒,就應(yīng)該在設(shè)置新屬性值時(shí)拷貝一份鸽照。

在對(duì)象內(nèi)部盡量直接訪問實(shí)例變量

1、訪問實(shí)例變量不經(jīng)過objc的方法派發(fā)(method dispatch)颠悬,所以速度更快矮燎。在這種情況下,編譯器所生成的代碼會(huì)直接訪問保存對(duì)象實(shí)例變量的那塊內(nèi)存赔癌。
2诞外、直接訪問實(shí)例變量,不會(huì)調(diào)用getter/setter方法
如果需要使用KVO或懶加載灾票,還是得使用屬性
在對(duì)象內(nèi)部讀取數(shù)據(jù)時(shí)峡谊,應(yīng)該直接通過實(shí)例變量來讀,而寫入數(shù)據(jù)時(shí)刊苍,應(yīng)該通過屬性來寫既们。
在初始化方法及dealloc方法中,總是應(yīng)該直接通過實(shí)例變量來讀寫數(shù)據(jù)正什。
有時(shí)會(huì)使用惰性初始化技術(shù)配置某份數(shù)據(jù)啥纸,這種情況下,需要通過屬性來讀取數(shù)據(jù)婴氮。

理解“對(duì)象等同性”

NSObject協(xié)議中有兩個(gè)用于判斷等同性的關(guān)鍵方法:

-(Bool)isEqual:(id)object;
-(NSUInteger)hash;

若想檢測(cè)對(duì)象的等同性斯棒,請(qǐng)?zhí)峁癷sEqual:”與hash方法盾致。
相同的對(duì)象必須具有相同的hash碼,但是兩個(gè)hash碼相同的對(duì)象卻未必相同荣暮。
不要盲目的逐個(gè)監(jiān)測(cè)每條屬性庭惜,而是應(yīng)該依照具體需求來制定檢測(cè)方案。
編寫hash方法時(shí)渠驼,應(yīng)該使用計(jì)算速度快而且哈希碼碰撞幾率低的算法蜈块。

理解objc_msgSend的作用

id returnValue = [someObject messageName:parameter];

someObject叫做receiver,messageName叫做selector迷扇,selector與參數(shù)合起來稱為message百揭。編譯器看到消息后,將其轉(zhuǎn)換為一條標(biāo)準(zhǔn)的C語言函數(shù)調(diào)用蜓席,如下

id returnValue = objc_msgSend(someObject,@selector(messageName:) parameter);

消息由receiver器一,selector及參數(shù)構(gòu)成。給某對(duì)象“發(fā)送消息”也就相當(dāng)于在該對(duì)象上調(diào)用方法厨内。
發(fā)給某對(duì)象的全部消息都要由“動(dòng)態(tài)消息派發(fā)系統(tǒng)”來處理祈秕,該系統(tǒng)會(huì)查出對(duì)應(yīng)的方法,并執(zhí)行其代碼雏胃。

理解消息轉(zhuǎn)發(fā)機(jī)制

什么是消息轉(zhuǎn)發(fā)请毛?當(dāng)對(duì)象接收到無法解讀的消息后,就會(huì)啟動(dòng)消息轉(zhuǎn)發(fā)機(jī)制瞭亮。

消息轉(zhuǎn)發(fā)分為兩個(gè)階段方仿。第一階段先征詢接收者所屬的類,看其是否能動(dòng)態(tài)添加方法统翩,已處理當(dāng)前這個(gè)“未知的selector”仙蚜,這叫做“動(dòng)態(tài)方法解析”。第二階段涉及“完整的消息轉(zhuǎn)發(fā)機(jī)制”厂汗。如果運(yùn)行期系統(tǒng)已經(jīng)把第一階段執(zhí)行完了委粉,那么接收者自己就無法再以動(dòng)態(tài)新增方法的手段來響應(yīng)包含該selector的消息了。此時(shí)運(yùn)行期系統(tǒng)就會(huì)請(qǐng)求接收者以其他手段來處理與消息相關(guān)的方法調(diào)用娶桦。細(xì)分為兩步:首先贾节,讓接收者看看有沒有其他對(duì)象能處理這條消息。如果有衷畦,則運(yùn)行期系統(tǒng)會(huì)把消息轉(zhuǎn)給那個(gè)接收者氮双,于是消息轉(zhuǎn)發(fā)結(jié)束。如果沒有這個(gè)“備援接收者”霎匈,則啟動(dòng)完整的消息轉(zhuǎn)發(fā)機(jī)制,運(yùn)行期系統(tǒng)會(huì)把與消息有關(guān)的全部細(xì)節(jié)封裝到NSInvocation對(duì)象中送爸,再給接收者最后一次機(jī)會(huì)铛嘱,令其設(shè)法解決當(dāng)前還未處理的這條消息暖释。

消息轉(zhuǎn)發(fā)機(jī)制流程圖

若對(duì)象無法響應(yīng)某個(gè)selector,則進(jìn)入消息轉(zhuǎn)發(fā)流程墨吓。
通過運(yùn)行期的動(dòng)態(tài)方法解析功能球匕,我們可以在需要用到某個(gè)方法時(shí)再將其加入類中。
對(duì)象可以將其無法解讀的某些selector轉(zhuǎn)交給其他對(duì)象處理帖烘。
經(jīng)過上述兩步后亮曹,如果還是沒辦法處理selector,那就啟動(dòng)完整的消息轉(zhuǎn)發(fā)機(jī)制秘症。

用method swizzling調(diào)試黑盒方法

在runtime中照卦,可以向類中新增或替換selector所對(duì)應(yīng)的方法實(shí)現(xiàn)。
使用另一份實(shí)現(xiàn)來替換原有的方法實(shí)現(xiàn)乡摹,這道工序叫做method swizzling役耕,開發(fā)者常用此技術(shù)向原有視線中添加功能。
一般來說聪廉,只有調(diào)試程序的時(shí)候才需要在runtime中修改方法實(shí)現(xiàn)瞬痘,這種做法不宜濫用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末板熊,一起剝皮案震驚了整個(gè)濱河市框全,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌干签,老刑警劉巖津辩,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異筒严,居然都是意外死亡丹泉,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門鸭蛙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來摹恨,“玉大人,你說我怎么就攤上這事娶视∩购澹” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵肪获,是天一觀的道長寝凌。 經(jīng)常有香客問我,道長孝赫,這世上最難降的妖魔是什么较木? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮青柄,結(jié)果婚禮上伐债,老公的妹妹穿的比我還像新娘预侯。我一直安慰自己,他們只是感情好峰锁,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布萎馅。 她就那樣靜靜地躺著,像睡著了一般虹蒋。 火紅的嫁衣襯著肌膚如雪糜芳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天魄衅,我揣著相機(jī)與錄音峭竣,去河邊找鬼。 笑死徐绑,一個(gè)胖子當(dāng)著我的面吹牛邪驮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播傲茄,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼毅访,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了盘榨?” 一聲冷哼從身側(cè)響起喻粹,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎草巡,沒想到半個(gè)月后守呜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡山憨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年查乒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片郁竟。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡玛迄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出棚亩,到底是詐尸還是另有隱情蓖议,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布讥蟆,位于F島的核電站勒虾,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏瘸彤。R本人自食惡果不足惜修然,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧愕宋,春花似錦婆翔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽潭陪。三九已至雄妥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間依溯,已是汗流浹背老厌。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留黎炉,地道東北人枝秤。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像慷嗜,于是被迫代替她去往敵國和親淀弹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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