本文主要對(duì)書(shū)中每個(gè)章節(jié)的要點(diǎn)進(jìn)行梳理.
第1章.熟悉Objective - C
第1條.了解Objective-C語(yǔ)言的起源
- 要點(diǎn)
Objective-C為C語(yǔ)言添加了面向?qū)ο筇匦裕瞧涑溺琛bjective-C使用動(dòng)態(tài)綁定的消息結(jié)構(gòu)咪笑,也就是說(shuō)犯祠,在運(yùn)行時(shí)才會(huì)檢查對(duì)象類型豆瘫。接收一條消息之后构捡,究竟應(yīng)執(zhí)行何種代碼偷俭,由運(yùn)行環(huán)境而非編譯器來(lái)決定浦箱。
理解C語(yǔ)言的核心概念有助于寫(xiě)好Objective-C程序。尤其要掌握內(nèi)存模型與指針制妄。
第2條.在類的頭文件中盡量少引入其他頭文件
- 要點(diǎn)
除非確有必要援奢,否則不要引入頭文件。一般來(lái)說(shuō)忍捡,應(yīng)在某個(gè)類的頭文件中使用向前聲明來(lái)提及別的類集漾,并在實(shí)現(xiàn)文件中引入那些類的頭文件。這樣做可以盡量降低類之間的耦合(coupling)砸脊。
有時(shí)無(wú)法使用向前聲明具篇,比如要聲明某個(gè)類遵循一項(xiàng)協(xié)議。這種情況下凌埂,盡量把“該類遵循某協(xié)議”的這條聲明移至"class-continuation分類"
中驱显。如果不行的話,就把協(xié)議單獨(dú)放在一個(gè)頭文件中,然后將其引入埃疫。
第3條.多用字面量語(yǔ)法少用與之等價(jià)的方法
- 要點(diǎn)
應(yīng)該使用字面量語(yǔ)法來(lái)創(chuàng)建字符串伏恐、數(shù)值、數(shù)組栓霜、字典翠桦。與創(chuàng)建此類對(duì)象的常規(guī)方法相比,這么做更加簡(jiǎn)明扼要胳蛮。
應(yīng)該通過(guò)取下標(biāo)操作來(lái)訪問(wèn)數(shù)組下標(biāo)或字典中的鍵所對(duì)應(yīng)的元素销凑。
用字面量語(yǔ)法創(chuàng)建數(shù)組或字典時(shí),若值中有nil
仅炊,則會(huì)拋出異常斗幼。因此,務(wù)必確保值里不含nil
抚垄。
第4條.多用類型常量少用define預(yù)處理器指令
- 要點(diǎn)
不要用預(yù)處理指令定義常量蜕窿。這樣定義出來(lái)的常量不含類型信息,編譯器只是會(huì)在編譯前據(jù)此執(zhí)行查找與替換操作呆馁。即使有人重新定義了常量值桐经,編譯器也不會(huì)產(chǎn)生警告信息,這將導(dǎo)致應(yīng)用程序中的常量值不一致智哀。
在實(shí)現(xiàn)文件中使用static const來(lái)定義"只在編譯單元內(nèi)可見(jiàn)的常量"(translation-unit-specific constant)次询。由于此類常量不在全局符號(hào)表中荧恍,所以無(wú)需為其名稱加前綴瓷叫。
在頭文件中使用extern
來(lái)聲明全局常量,并在相關(guān)實(shí)現(xiàn)文件中定義其值送巡。這種常量要出現(xiàn)在全局符號(hào)表中摹菠,所以其名稱要加以區(qū)隔,通常用與之相關(guān)的類名做前綴骗爆。
第5條.用枚舉表示狀態(tài)次氨、選項(xiàng)、狀態(tài)碼
- 要點(diǎn)
應(yīng)該用枚舉來(lái)表示狀態(tài)機(jī)的狀態(tài)摘投、傳遞給方法的選項(xiàng)以及狀態(tài)碼等值煮寡,給這些值起個(gè)易懂的名字。
如果把傳遞給某個(gè)方法的選項(xiàng)表示為枚舉型犀呼,而多個(gè)選項(xiàng)又可同時(shí)使用幸撕,那么就將各選項(xiàng)值定義為2的冪,以便通過(guò)按位或操作將其組合起來(lái)外臂。
用NS_ENUM與NS_OPTIONS宏來(lái)定義枚舉類型坐儿,并指明其底層數(shù)據(jù)類型。這樣做可以確保枚舉是用開(kāi)發(fā)者所選的底層數(shù)據(jù)類型實(shí)現(xiàn)出來(lái)的,而不會(huì)采用編譯器所選的類型貌矿。
在處理枚舉類型的switch語(yǔ)句中不要實(shí)現(xiàn)default分支炭菌。這樣的話,加入新枚舉之后逛漫,編譯器就會(huì)提示開(kāi)發(fā)者:switch語(yǔ)句并未處理所有的枚舉黑低。
第2章.對(duì)象、消息尽楔、運(yùn)行期(runtime)
第6條.理解“屬性”這一概念
- 要點(diǎn)
可以通過(guò)
@property
語(yǔ)法來(lái)定義對(duì)象中所封裝的數(shù)據(jù)投储。
通過(guò)"特質(zhì)"
來(lái)指定存儲(chǔ)數(shù)據(jù)所需的正確語(yǔ)義。
在設(shè)置屬性所對(duì)應(yīng)的實(shí)例變量時(shí)阔馋,一定要遵從該屬性所聲明的語(yǔ)義玛荞。
開(kāi)發(fā)iOS程序時(shí),應(yīng)該使用nonatomic
屬性呕寝,因?yàn)閍tomic屬性會(huì)嚴(yán)重影響性能勋眯。
第7條.在對(duì)象內(nèi)部盡量直接訪問(wèn)實(shí)例變量
- 要點(diǎn)
在對(duì)象內(nèi)部讀取數(shù)據(jù)時(shí),應(yīng)該直接通過(guò)實(shí)例變量來(lái)讀下梢,而寫(xiě)入數(shù)據(jù)時(shí)客蹋,應(yīng)該通過(guò)屬性來(lái)寫(xiě)。
在初始化方法及dealloc方法中孽江,總是應(yīng)該直接通過(guò)實(shí)例變量來(lái)讀寫(xiě)數(shù)據(jù)讶坯。
有時(shí)會(huì)使用惰性初始化技術(shù)配置某份數(shù)據(jù),這種情況下岗屏,需要通過(guò)屬性來(lái)讀取數(shù)據(jù)辆琅。
第8條.理解“對(duì)象等同性”這一概念
- 要點(diǎn)
若想檢測(cè)對(duì)象的等同性,請(qǐng)?zhí)峁?code>“isEqual:”與
hash
方法这刷。
相同的對(duì)象必須具有相同的哈希碼婉烟,但是兩個(gè)哈希碼相同的對(duì)象卻未必相同。
不要盲目的逐個(gè)監(jiān)測(cè)每條屬性暇屋,而是應(yīng)該依照具體需求來(lái)制定檢測(cè)方案似袁。
編寫(xiě)hash
方法時(shí),應(yīng)該使用計(jì)算速度快而且哈希碼碰撞幾率低的算法咐刨。
第9條.以“類族模式”隱藏實(shí)現(xiàn)細(xì)節(jié)
- 要點(diǎn)
類族模式可以把實(shí)現(xiàn)細(xì)節(jié)隱藏在一套簡(jiǎn)單的公共接口后面昙衅。
系統(tǒng)框架中經(jīng)常使用類族。
從類族的公共抽象基類中繼承子類時(shí)要當(dāng)心定鸟,若有開(kāi)發(fā)文檔而涉,則應(yīng)首先閱讀。
第10條.在既有類中仔粥,使用關(guān)聯(lián)對(duì)象(Associated Object)存放自定義數(shù)據(jù)
- 要點(diǎn)
可以通過(guò)
“關(guān)聯(lián)對(duì)象”
機(jī)制來(lái)把兩個(gè)對(duì)象連起來(lái)婴谱。
定義關(guān)聯(lián)對(duì)象時(shí)可指定內(nèi)存管理語(yǔ)義蟹但,用以模仿定義屬性時(shí)所采用的“擁有關(guān)系”
與“非擁有關(guān)系”
。
只有在其他做法不可行時(shí)才應(yīng)選用關(guān)聯(lián)對(duì)象谭羔,因?yàn)檫@種做法通常會(huì)引入難于查找的bug华糖。
第11條.理解objc_msgSend的作用
- 要點(diǎn)
消息由接收者,選擇子(selector)及參數(shù)構(gòu)成瘟裸。給某對(duì)象
“發(fā)送消息”(invoke a message)
也就相當(dāng)于在該對(duì)象上"調(diào)用方法"(call a method)
客叉。
發(fā)給某對(duì)象的全部消息都要由“動(dòng)態(tài)消息派發(fā)系統(tǒng)”
來(lái)處理,該系統(tǒng)會(huì)查出對(duì)應(yīng)的方法话告,并執(zhí)行其代碼兼搏。
第12條.理解消息轉(zhuǎn)發(fā)機(jī)制
- 要點(diǎn)
若對(duì)象無(wú)法響應(yīng)某個(gè)選擇子(selector),則進(jìn)入消息轉(zhuǎn)發(fā)流程沙郭。
通過(guò)運(yùn)行期的動(dòng)態(tài)方法解析功能佛呻,我們可以在需要用到某個(gè)方法時(shí)再將其加入類中。
對(duì)象可以將其無(wú)法解讀的某些選擇子(selector)轉(zhuǎn)交給其他對(duì)象處理病线。
經(jīng)過(guò)上述兩步后吓著,如果還是沒(méi)辦法處理選擇子(selector),那就啟動(dòng)完整的消息轉(zhuǎn)發(fā)機(jī)制送挑。
第13條.用"方法調(diào)配技術(shù)"(method swizzling)調(diào)試黑盒方法
- 要點(diǎn)
在運(yùn)行期(runtime)中绑莺,可以向類中新增或替換選擇子(selector)所對(duì)應(yīng)的方法實(shí)現(xiàn)。
使用另一份實(shí)現(xiàn)來(lái)替換原有的方法實(shí)現(xiàn)惕耕,這道工序叫做"方法調(diào)配"(method swizzling)
纺裁,開(kāi)發(fā)者常用此技術(shù)向原有實(shí)現(xiàn)中添加功能。
一般來(lái)說(shuō)司澎,只有調(diào)試程序的時(shí)候才需要在runtime中修改方法實(shí)現(xiàn)欺缘,這種做法不宜濫用。
第14條.理解“類對(duì)象”的用意
- 要點(diǎn)
每個(gè)實(shí)例都有一個(gè)指向
Class對(duì)象
的指針惭缰,用以表明其類型浪南,而這些Class對(duì)象則構(gòu)成了類的繼承體系笼才。
如果對(duì)象類型無(wú)法在編譯期確定漱受,那么就應(yīng)該使用類型信息查詢方法來(lái)探知。
盡量使用類型信息查詢方法來(lái)確定對(duì)象類型骡送,而不要直接比較類對(duì)象昂羡,因?yàn)槟承?duì)象可能實(shí)現(xiàn)了消息轉(zhuǎn)發(fā)功能。
第3章.接口與API設(shè)計(jì)
第15條.用前綴避免命名空間沖突
- 要點(diǎn)
選擇與你公司摔踱、應(yīng)用程序或者二者皆有關(guān)聯(lián)之名稱作為類名的前綴虐先,并在所有代碼中均使用這一前綴。
若自己所開(kāi)發(fā)的程序庫(kù)中用到了第三方庫(kù)派敷,則應(yīng)為其中的名稱加上前綴蛹批。
第16條.提供“全能初始化方法”
- 要點(diǎn)
在類中提供一個(gè)全能初始化方法撰洗,并于文檔里指明。其它初始化方法均應(yīng)調(diào)用此方法腐芍。
若全能初始化方法與超類不同差导,則需覆寫(xiě)超類中的對(duì)應(yīng)方法。
如果超類的初始化方法并不適用于子類猪勇,那么應(yīng)該覆寫(xiě)這個(gè)超類方法设褐,并在其中拋出異常。
第17條.實(shí)現(xiàn)description方法
- 要點(diǎn)
實(shí)現(xiàn)
description
方法返回一個(gè)有意義的字符串泣刹,用以描述該實(shí)例助析。
若想在調(diào)試時(shí)打印出更詳盡的對(duì)象描述信息,則應(yīng)實(shí)現(xiàn)debugDescription
方法椅您。
第18條.盡量使用不可變對(duì)象
- 要點(diǎn)
盡量創(chuàng)建不可變的對(duì)象外冀。
若某屬性僅可于對(duì)象內(nèi)部修改,則在“class-continuation分類”中將其由readonly屬性擴(kuò)展為readwrite屬性掀泳。
不要把可變的collection作為屬性公開(kāi)锥惋,而應(yīng)提供相關(guān)方法,以此修改對(duì)象中的可變collection开伏。
第19條.使用清晰而協(xié)調(diào)的命名方式
- 要點(diǎn)
起名時(shí)應(yīng)遵從標(biāo)準(zhǔn)的Objective-C命名規(guī)范膀跌,這樣創(chuàng)建出來(lái)的接口更容易為開(kāi)發(fā)者所理解。
方法名要言簡(jiǎn)意賅固灵,從左至右讀起來(lái)要像個(gè)日常用語(yǔ)中的句子才好捅伤。
方法名里不要使用縮略后的類型名稱。
給方法起名時(shí)的第一要?jiǎng)?wù)就是確保其風(fēng)格與你自己的代碼或所要集成的框架相符巫玻。
第20條.為私有方法名加前綴
- 要點(diǎn)
給私有方法的名稱加上前綴丛忆,這樣可以很容易地將其同公共方法區(qū)分開(kāi)。
不要單用一個(gè)下劃線做私有方法的前綴仍秤,因?yàn)檫@種做法的預(yù)留給蘋(píng)果公司用的熄诡。
第21條.理解Objective-C錯(cuò)誤模型
- 要點(diǎn)
只有發(fā)生了可使整個(gè)應(yīng)用程序崩潰的嚴(yán)重錯(cuò)誤時(shí),才應(yīng)使用異常诗力。
在錯(cuò)誤不那么嚴(yán)重的情況下凰浮,可以指派"委托方法"(delegate method)
來(lái)處理錯(cuò)誤,也可把錯(cuò)誤信息放在NSError對(duì)象里苇本,經(jīng)由"輸出參數(shù)"
返回給調(diào)用者袜茧。
第22條.理解NSCopying協(xié)議
- 要點(diǎn)
若想令自己所寫(xiě)的對(duì)象具有拷貝功能,則需實(shí)現(xiàn)
NSCopying
協(xié)議瓣窄。
如果自定義的對(duì)象分為可變版本與不可變版本笛厦,那么就要同時(shí)實(shí)現(xiàn)NSCopying
與NSMutableCopying
協(xié)議。
復(fù)制對(duì)象時(shí)需決定采用淺拷貝還是深拷貝俺夕,一般情況下應(yīng)該盡量執(zhí)行淺拷貝裳凸。
如果你所寫(xiě)的對(duì)象需要深拷貝贱鄙,那么可考慮新增一個(gè)專門(mén)執(zhí)行深拷貝的方法。
第4章.協(xié)議與分類
第23條.通過(guò)委托與數(shù)據(jù)源協(xié)議進(jìn)行對(duì)象間通信
- 要點(diǎn)
委托模式為對(duì)象提供了一套接口姨谷,使其可由此將相關(guān)事件告知其他對(duì)象贰逾。
將委托對(duì)象應(yīng)該支持的接口定義成協(xié)議,在協(xié)議中把可能需要處理的事件定義成方法菠秒。
當(dāng)某對(duì)象需要從另外一個(gè)對(duì)象中獲取數(shù)據(jù)時(shí)疙剑,可使用委托模式。在這種情況下践叠,該模式亦稱"數(shù)據(jù)源協(xié)議"(data source protocal)
言缤。
若有必要,可實(shí)現(xiàn)含有位段的結(jié)構(gòu)體禁灼,將委托對(duì)象是否能響應(yīng)相關(guān)協(xié)議方法這一信息緩存至其中管挟。
第24條.將類的實(shí)現(xiàn)代碼分散到便于管理的數(shù)個(gè)分類之中
- 要點(diǎn)
使用分類機(jī)制把類的實(shí)現(xiàn)代碼劃分成易于管理的小塊。
將應(yīng)該視為私有的方法歸入名叫Private的分類中弄捕,以隱藏實(shí)現(xiàn)細(xì)節(jié)僻孝。
第25條.總是為第三方類的分類名稱加前綴
- 要點(diǎn)
向第三方類中添加分類時(shí),總應(yīng)給其名稱加上你專用的前綴守谓。
向第三方類中添加分類時(shí)穿铆,總應(yīng)給其中的方法名加上你專用的前綴。
第26條.勿在分類中聲明屬性
- 要點(diǎn)
把封裝數(shù)據(jù)所用的全部屬性都定義在主接口里斋荞。
在"class-continuation"
分類之外的其他分類中荞雏,可以定義存取方法,但盡量不要定義屬性平酿。
第27條.使用"class-continuation分類"隱藏實(shí)現(xiàn)細(xì)節(jié)
- 要點(diǎn)
通過(guò)
"class-continuation分類"
向類中新增實(shí)例變量凤优。
如果某屬性在主接口中聲明為"只讀"
,而類的內(nèi)部又要用設(shè)置方法修改此屬性蜈彼,那么就在"class-continuation分類"
中將其擴(kuò)展為"可讀寫(xiě)"
筑辨。
把私有方法的原型聲明在"class-continuation分類"
里面。
若想使類遵循的協(xié)議不為人所知幸逆,則可于class-continuation分類中聲明棍辕。
第28條.通過(guò)協(xié)議提供匿名對(duì)象
- 要點(diǎn)
協(xié)議可在某種程度上提供匿名類型。具體的對(duì)象類型可以淡化成遵從某協(xié)議的id類型秉颗,協(xié)議里規(guī)定了對(duì)象所應(yīng)實(shí)現(xiàn)的方法痢毒。
使用匿名對(duì)象來(lái)隱藏類型名稱或類名送矩。
如果具體類型不重要蚕甥,重要的是對(duì)象能夠響應(yīng)(定義在協(xié)議里的)特定方法,那么可使用匿名對(duì)象來(lái)表示栋荸。
第5章.內(nèi)存管理
第29條.理解引用計(jì)數(shù)
- 要點(diǎn)
引用計(jì)數(shù)機(jī)制通過(guò)可以遞增遞減的計(jì)數(shù)器來(lái)管理內(nèi)存菇怀。對(duì)象創(chuàng)建好之后凭舶,其保留計(jì)數(shù)至少為1.若保留計(jì)數(shù)為正,則對(duì)象繼續(xù)存活爱沟。當(dāng)保留計(jì)數(shù)降為0時(shí)帅霜,對(duì)象就被銷毀了。
在對(duì)象生命期中呼伸,其余對(duì)象通過(guò)引用來(lái)保留或釋放此對(duì)象身冀。保留與釋放操作分別會(huì)遞增及遞減保留計(jì)數(shù)。
第30條.以ARC簡(jiǎn)化引用計(jì)數(shù)
- 要點(diǎn)
在ARC之后括享,程序員就無(wú)須擔(dān)心內(nèi)存管理問(wèn)題了搂根。使用ARC來(lái)編程,可省去類中的許多"樣板代碼"铃辖。
ARC管理對(duì)象生命期的辦法基本上就是:在合適的地方插入"保留"
及"釋放"
操作剩愧。在ARC環(huán)境下,變量的內(nèi)存管理語(yǔ)義可以通過(guò)修飾符指明, 而原來(lái)則需要手工執(zhí)行"保留"及"釋放"操作娇斩。
由方法所返回的對(duì)象,其內(nèi)存管理語(yǔ)義總是通過(guò)方法名來(lái)體現(xiàn)仁卷。ARC將此確定為開(kāi)發(fā)者必須遵守的規(guī)則。
ARC只負(fù)責(zé)管理Objective-C對(duì)象的內(nèi)存犬第。尤其要注意:CoreFoundation對(duì)象
不歸ARC管理锦积,開(kāi)發(fā)者必須適時(shí)調(diào)用CFRetain/CFRelease。
第31條.在dealloc方法中只釋放引用并解除監(jiān)聽(tīng)
- 要點(diǎn)
在dealloc方法里歉嗓,應(yīng)該做的事情就是釋放指向其它對(duì)象的引用充包,并取消原來(lái)訂閱的
"鍵值觀測(cè)"(KVO)
或NSNotificationCenter等通知,不要做其他事情遥椿。
如果對(duì)象持有文件描述符等系統(tǒng)資源基矮,那么應(yīng)該專門(mén)編寫(xiě)一個(gè)方法來(lái)釋放此種資源。這樣的類要和其使用者約定 : 用完資源后必須調(diào)用close方法冠场。
執(zhí)行異步任務(wù)的方法不應(yīng)在dealloc里調(diào)用家浇;只能在正常狀態(tài)下執(zhí)行的那些方法也不應(yīng)在dealloc里調(diào)用,因?yàn)榇藭r(shí)對(duì)象已處于正在回收的狀態(tài)了碴裙。
第32條.編寫(xiě)"異常安全代碼"時(shí)留意內(nèi)存管理問(wèn)題
- 要點(diǎn)
捕獲異常時(shí)钢悲,一定要注意將try塊內(nèi)所創(chuàng)立的對(duì)象清理干凈。
在默認(rèn)情況下舔株,ARC不生成安全處理異常所需的清理代碼莺琳。開(kāi)啟編譯器標(biāo)志后,可生成這種代碼载慈,不過(guò)會(huì)導(dǎo)致應(yīng)用程序變大惭等,而且會(huì)降低運(yùn)行效率。
第33條.以弱引用避免保留環(huán)(循環(huán)引用)
- 要點(diǎn)
將某些引用設(shè)為
weak
办铡,可避免出現(xiàn)"保留環(huán)"(循環(huán)引用)
辞做。
weak
引用可以自動(dòng)清空琳要,也可以不自動(dòng)清空。自動(dòng)清空(autoniling)是隨著ARC而引入的新特性秤茅,由運(yùn)行期系統(tǒng)(runtime)來(lái)實(shí)現(xiàn)稚补,在具備自動(dòng)清空功能的弱引用上,可以隨意讀取其數(shù)據(jù)框喳,因?yàn)檫@種引用不會(huì)指向已經(jīng)回收過(guò)的對(duì)象课幕。
第34條.以"自動(dòng)釋放池塊"降低內(nèi)存峰值
- 要點(diǎn)
自動(dòng)釋放池排布在棧中,對(duì)象收到
autorelease
消息后五垮,系統(tǒng)將其放入最頂端的池里撰豺。
合理運(yùn)用自動(dòng)釋放池,可降低應(yīng)用程序的內(nèi)存峰值拼余。
@autoreleasepool
這種新式寫(xiě)法能創(chuàng)建出更為輕便的自動(dòng)釋放池污桦。
第35條.用“僵尸對(duì)象”調(diào)試內(nèi)存管理問(wèn)題
- 要點(diǎn)
系統(tǒng)在回收對(duì)象時(shí),可以不將其真的回收匙监,而是把它轉(zhuǎn)化為僵尸對(duì)象凡橱。通過(guò)環(huán)境變量
NSZombieEnabled
可開(kāi)啟此功能。
系統(tǒng)會(huì)修改對(duì)象的isa指針亭姥,令其指向特殊的僵尸類稼钩,從而使該對(duì)象變?yōu)榻┦瑢?duì)象。僵尸類能夠響應(yīng)所有的選擇子(selector),響應(yīng)方式為:打印一條包含消息內(nèi)容及其接受者的消息达罗,然后終止應(yīng)用程序坝撑。
第36條.不要使用retainCount
- 要點(diǎn)
對(duì)象的保留計(jì)數(shù)看似有用,實(shí)則不然粮揉,因?yàn)槿魏谓o定時(shí)間點(diǎn)上的
"絕對(duì)保留計(jì)數(shù)"(absolute retainCount)
都無(wú)法反映對(duì)象生命期的全貌巡李。
引入ARC后,retainCount方法就正式廢止了扶认,在ARC下調(diào)用該方法會(huì)導(dǎo)致編譯器報(bào)錯(cuò)侨拦。
第6章.塊(block)與大中樞派發(fā)(GCD)
第37條.理解"塊"(block)這一概念
- 要點(diǎn)
block是C、C++辐宾、Objective-C中的詞法閉包狱从。
block可接收參數(shù),也可返回值叠纹。
block可以分配在椉狙校或堆上,也可以是全局的誉察。分配在棧上的block可拷貝到堆里与涡,這樣的話,就和標(biāo)準(zhǔn)的Objective-C對(duì)象一樣,具備引用計(jì)數(shù)了递沪。
第38條.為常用的block類型創(chuàng)建typedef
- 要點(diǎn)
以
typedef
重新定義block類型豺鼻,可以令block變量用起來(lái)更加簡(jiǎn)單综液。
定義新類型時(shí)應(yīng)遵循現(xiàn)有的命名習(xí)慣款慨,勿使其名稱與別的的類型相沖突。
不妨為同一個(gè)block簽名定義多個(gè)類型別名谬莹。如果要重構(gòu)的代碼使用了block類型的某個(gè)別名檩奠,那么只需修改相應(yīng)的typedef中的block簽名即可,無(wú)需改動(dòng)其他typedef附帽。
第39條.用handler塊降低代碼分散程度
- 要點(diǎn)
在創(chuàng)建對(duì)象時(shí)埠戳,使用內(nèi)聯(lián)的handler塊將相關(guān)業(yè)務(wù)邏輯一并聲明。
在有多個(gè)實(shí)例需要監(jiān)控時(shí)蕉扮,如果采用委托模式整胃,那么經(jīng)常需要根據(jù)傳入的對(duì)象來(lái)切換,而若改用handler塊來(lái)實(shí)現(xiàn)喳钟,則可直接將塊(block)與相關(guān)對(duì)象放在一起屁使。
設(shè)計(jì)API時(shí)如果用到了handler塊,那么可以增加一個(gè)參數(shù)奔则,使調(diào)用者可通過(guò)此參數(shù)來(lái)決定應(yīng)該把塊(block)安排在哪個(gè)隊(duì)列上執(zhí)行蛮寂。
第40條.用block引用其所屬對(duì)象時(shí)不要出現(xiàn)循環(huán)引用
- 要點(diǎn)
如果block所捕獲的對(duì)象直接或間接的保留了塊(block)本身,那么就得當(dāng)心循環(huán)引用的問(wèn)題易茬。
一定要找個(gè)適當(dāng)?shù)臅r(shí)機(jī)解除保留環(huán)(循環(huán)引用)酬蹋,而不能把責(zé)任推給API的調(diào)用者。
第41條.多用派發(fā)隊(duì)列抽莱,少用同步鎖
- 要點(diǎn)
派發(fā)隊(duì)列可用來(lái)表述同步語(yǔ)義(synchronous semantic)范抓,這種做法要比使用
@synchronized塊
或NSLock對(duì)象
更簡(jiǎn)單。
將同步與異步派發(fā)結(jié)合起來(lái)食铐,可以實(shí)現(xiàn)與普通加鎖機(jī)制一樣的同步行為尉咕,而這么做卻不會(huì)阻塞執(zhí)行異步派發(fā)的線程。
使用同步隊(duì)列及柵欄塊璃岳,可以領(lǐng)同步行為更加高效年缎。
第42條.多用GCD,少用performSelector系列方法
- 要點(diǎn)
performSelector系列方法在內(nèi)存管理方面容易有疏失铃慷。它無(wú)法確定將要執(zhí)行的選擇子(selector)具體是什么单芜,因而ARC編譯器就無(wú)法插入適當(dāng)?shù)膬?nèi)存管理方法。
performSelector系列方法所能處理的選擇子(selector)太過(guò)局限了犁柜,選擇子(selector)的返回值類型及發(fā)送給方法的參數(shù)個(gè)數(shù)都受到限制洲鸠。
如果想把任務(wù)放在另一個(gè)線程上執(zhí)行,那么最好不要用performSelector系列方法而是應(yīng)該把任務(wù)封裝到塊(block)里然后調(diào)用大中樞派發(fā)(GCD)機(jī)制的相關(guān)方法來(lái)實(shí)現(xiàn)。
第43條.掌握GCD及操作隊(duì)列的使用時(shí)機(jī)
- 要點(diǎn)
在解決多線程與任務(wù)管理問(wèn)題時(shí)扒腕,派發(fā)隊(duì)列并非唯一方案绢淀。
操作隊(duì)列提供了一套高層的Objective-C API,能實(shí)現(xiàn)純GCD所具備的絕大部分功能瘾腰,而且還能完成一些更為復(fù)雜的操作皆的,那些操作若改用GCD來(lái)實(shí)現(xiàn),則需另外編寫(xiě)代碼蹋盆。
第44條.通過(guò)Dispatch Group機(jī)制,根據(jù)系統(tǒng)資源狀況來(lái)執(zhí)行任務(wù)
- 要點(diǎn)
一系列任務(wù)可歸入一個(gè)dispatch group之中费薄。開(kāi)發(fā)者可以在這組任務(wù)執(zhí)行完畢時(shí)獲得通知。
通過(guò)dispatch group栖雾,可以在并發(fā)式派發(fā)隊(duì)列里同時(shí)執(zhí)行多項(xiàng)任務(wù)楞抡。此時(shí)GCD會(huì)根據(jù)系統(tǒng)資源狀況來(lái)調(diào)度這些并發(fā)執(zhí)行的任務(wù)。開(kāi)發(fā)者若自己來(lái)實(shí)現(xiàn)此功能析藕,則需編寫(xiě)大量代碼召廷。
第45條.使用dispatch_once來(lái)執(zhí)行只需運(yùn)行一次的線程安全代碼
- 要點(diǎn)
經(jīng)常需要編寫(xiě)
"只需執(zhí)行一次的線程安全代碼"(thread-safe single-code execution)
。通過(guò)GCD所提供的dispatch_once函數(shù)
账胧,很容易就能實(shí)現(xiàn)此功能竞慢。
標(biāo)記應(yīng)該聲明在static或global作用域中,這樣的話找爱,在把只需執(zhí)行一次的塊(block)傳給dispatch_once函數(shù)時(shí)梗顺,傳進(jìn)去的標(biāo)記也是相同的。
第46條.不要使用dispatch_get_current_queue
- 要點(diǎn)
dispatch_get_current_queue函數(shù)的行為常常與開(kāi)發(fā)者所預(yù)期的不同车摄。此函數(shù)已廢棄寺谤,只應(yīng)做調(diào)試之用。
由于派發(fā)隊(duì)列是按層級(jí)來(lái)組織的吮播,所以無(wú)法單用某個(gè)隊(duì)列對(duì)象來(lái)描述"當(dāng)前隊(duì)列"
這一概念变屁。
dispatch_get_current_queue函數(shù)用于解決由不可重入的代碼所引發(fā)的死鎖,然而能用此函數(shù)解決的問(wèn)題意狠,通常也能改用“隊(duì)列特定數(shù)據(jù)”
來(lái)解決粟关。
第7章.系統(tǒng)框架
第47條.熟悉系統(tǒng)框架
- 要點(diǎn)
許多系統(tǒng)框架都可以直接使用。其中最重要的是
Foundation
與CoreFoundation
环戈,這兩個(gè)框架提供了構(gòu)建應(yīng)用程序所需的許多核心功能闷板。
很多常見(jiàn)任務(wù)都能用框架來(lái)做,例如音頻與視頻處理院塞、網(wǎng)絡(luò)通信
數(shù)據(jù)管理等遮晚。
請(qǐng)記住:用純C寫(xiě)成的框架與用Objective-C寫(xiě)成的一樣重要拦止,若想成為優(yōu)秀的Objective-C開(kāi)發(fā)者县遣,應(yīng)該掌握C語(yǔ)言的核心概念糜颠。
第48條.多用塊枚舉,少用for循環(huán)
- 要點(diǎn)
遍歷collection有4種方式萧求。最基本的辦法是for循環(huán)其兴,其次是NSEnumerator遍歷方法及快速遍歷方法,最新夸政、最先進(jìn)的方式則是
"塊枚舉法"
元旬。
"塊枚舉法"
本身就能通過(guò)GCD來(lái)并發(fā)執(zhí)行遍歷操作,無(wú)需另行編寫(xiě)代碼秒梳。而采用其他遍歷方式則無(wú)法輕易實(shí)現(xiàn)這一點(diǎn)法绵。
若提前知道待遍歷的collection含有何種對(duì)象箕速,則應(yīng)修改塊簽名酪碘,指出對(duì)象的具體類型。
第49條.對(duì)自定義其內(nèi)存管理語(yǔ)義的collection使用無(wú)縫橋接
- 要點(diǎn)
通過(guò)無(wú)縫橋接技術(shù)盐茎,可以在
Foundation框架
中的Objective-C對(duì)象
與CoreFoundation框架
中的C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)
之前來(lái)回轉(zhuǎn)換兴垦。
在CoreFoundation層面創(chuàng)建collection時(shí),可以指定許多回調(diào)函數(shù)字柠,這些函數(shù)表示此collection應(yīng)如何處理其元素探越。然后,可運(yùn)用無(wú)縫橋接技術(shù)窑业,將其轉(zhuǎn)換成具備特殊內(nèi)存管理語(yǔ)義的Objective-C collection钦幔。
第50條.構(gòu)建緩存是選用NSCachae而非NSDictionary
- 要點(diǎn)
實(shí)現(xiàn)緩存時(shí)應(yīng)選用NSCache而非NSDictionary對(duì)象。因?yàn)镹SCache可以提供優(yōu)雅的自動(dòng)刪減功能常柄,而且是
"線程安全的"
鲤氢,此外,它與字典不同西潘,并不會(huì)拷貝鍵卷玉。
可以給NSCache對(duì)象設(shè)置上限,用以限制緩存中的對(duì)象總個(gè)數(shù)及"總成本"
喷市,而這些尺度則定義了緩存刪減其中對(duì)象的時(shí)機(jī)相种。但是絕對(duì)不要把這些尺度當(dāng)成可靠的"硬限制"(hard limit),他們僅對(duì)NSCache起指導(dǎo)作用品姓。
將NSPurgeableData與NSCache搭配使用寝并,可實(shí)現(xiàn)自動(dòng)清除數(shù)據(jù)的功能,也就是說(shuō)腹备,當(dāng)NSPurgeableData對(duì)象所占內(nèi)存為系統(tǒng)丟棄時(shí)衬潦,該對(duì)象自身也會(huì)從緩存中移除.
如果緩存使用得當(dāng)。那么應(yīng)用程序的響應(yīng)速度就能提高馏谨。只有那種"重新計(jì)算起來(lái)很費(fèi)事的"數(shù)據(jù)别渔,才值得放入緩存,比如那些需要從網(wǎng)絡(luò)獲取或從磁盤(pán)讀取的數(shù)據(jù)。
第51條.精簡(jiǎn)initialize與load的實(shí)現(xiàn)代碼
- 要點(diǎn)
在加載階段哎媚,如果實(shí)現(xiàn)了load方法喇伯,那么系統(tǒng)就會(huì)調(diào)用它。分類里也可以定義此方法拨与,類load方法要比分類中的先調(diào)用稻据。與其他方法不同,load方法不參與覆寫(xiě)機(jī)制买喧。
首次使用某個(gè)類之前捻悯,系統(tǒng)會(huì)向其發(fā)送initialize消息。由于此方法遵從普通的復(fù)寫(xiě)規(guī)則淤毛,所以通常應(yīng)該在里面判斷當(dāng)前要初始化的是哪個(gè)類今缚。
load與initialize方法都應(yīng)該實(shí)現(xiàn)的精簡(jiǎn)一些,這有助于保持應(yīng)用程序的響應(yīng)能力低淡,也能減少引入"依賴環(huán)"(interdependency cycle)
的幾率姓言。
無(wú)法在編譯期設(shè)定的全局常量,可以放在initialize方法里初始化蔗蹋。
第52條.別忘了NSTimer會(huì)保留其目標(biāo)對(duì)象
- 要點(diǎn)
NSTimer對(duì)象會(huì)保留其目標(biāo)何荚,直到計(jì)時(shí)器本身失效為止,調(diào)用invalidate方法可令計(jì)時(shí)器失效猪杭,另外餐塘,一次性的計(jì)時(shí)器在觸發(fā)完任務(wù)之后也會(huì)失效。
反復(fù)執(zhí)行任務(wù)的計(jì)時(shí)器(repeating timer)皂吮,很容易引入保留環(huán)(循環(huán)引用)戒傻,進(jìn)入過(guò)這種計(jì)時(shí)器的目標(biāo)對(duì)象又保留了計(jì)時(shí)器本身,那肯定會(huì)導(dǎo)致保留環(huán)(循環(huán)引用)涮较。這種保留環(huán)關(guān)系(循環(huán)引用)稠鼻,可能是直接發(fā)生的,也可能是通過(guò)對(duì)象圖里的其他對(duì)象間接發(fā)生的狂票。
可以擴(kuò)充NSTimer的功能候齿,用"塊"來(lái)打破保留環(huán)(循環(huán)引用)。不過(guò)闺属,除非NSTimer將來(lái)在公共接口里提供此功能慌盯,否則必須創(chuàng)建分類,將相關(guān)實(shí)現(xiàn)代碼加入其中掂器。
以上內(nèi)容為書(shū)中的重點(diǎn)部分,優(yōu)先整理,后續(xù)繼續(xù)整理對(duì)每個(gè)章節(jié)的具體講解.希望能幫助到你.
CSDN
iOS讀書(shū)筆記之Effective Objective-C 2.0