本文是《Effective Objective-C 2.0 -編寫高質(zhì)量 iOS 與 OS X 代碼的52個(gè)有效方法》一書的讀書筆記. 該書提出來了52條編寫代碼的建議, 并進(jìn)行分類及詳細(xì)闡述, 本文引用了書中的各章小節(jié), 并按自己的理解做出了適當(dāng)拓展, 希望可以盡量完整的體現(xiàn)出書中的關(guān)鍵信息.
熟悉 Objective-c
- 類的頭文件中盡量少引入其它頭文件
使用@class 關(guān)鍵字進(jìn)行前向聲明, 在頭文件定義類時(shí)可以不用引 用相關(guān)頭文件, 在實(shí)現(xiàn)代碼中再引入, 可以提高編譯效率, 還可以防止循環(huán)引用的發(fā)生.(繼承與非委托用途的協(xié)議除外) - 多用字面量語法
比調(diào)用構(gòu)函數(shù)更簡(jiǎn)明直觀 - 多用類型常量,少用#define預(yù)處理指令
使用static const 關(guān)鍵字定義帶有類型信息的常量(編譯時(shí)還是會(huì)像#define 一樣替換, 但是帶有了類型信息), 私有的常量應(yīng)該定義的實(shí)現(xiàn)文件中.
使用 extern 關(guān)鍵字定義全局常量(會(huì)放在全局符號(hào)表中), 能常用類名做前綴, 在頭文件中聲明, 在實(shí)現(xiàn)文件中 定義值 - 用枚舉表示狀態(tài), 選項(xiàng), 狀態(tài)碼
- 應(yīng)該用枚舉來表示狀態(tài)機(jī)的狀態(tài)枷莉、傳遞給方法的選項(xiàng)遺跡狀態(tài)碼等值址遇,給這些值起個(gè)易懂的名字白指。
- 如果把傳遞給某個(gè)方法的選項(xiàng)表示為枚舉型,而多個(gè)選項(xiàng)又可同時(shí)使用,那么就將各選項(xiàng)值定義為2的冪缎脾,以便通過按位或者操作將其組合起來深滚。
- 用NS_ENUM與NS_OPTIONS宏來定義枚舉類型,并指明其底層數(shù)據(jù)類型仪缸。這樣做可以確保枚舉是用開發(fā)者所選的底層數(shù)據(jù)類型實(shí)現(xiàn)出來的贵涵,而不會(huì)采用編譯器所選的類型。
- 在處理枚舉類型的switch語句中不要實(shí)現(xiàn)default分支恰画。這樣的話宾茂,加入新枚舉之后,編譯器就會(huì)提示開發(fā)者:switch語句并未處理所有的枚舉拴还。
對(duì)象跨晴、消息、運(yùn)行時(shí)相關(guān)
- 理解 property
- 可以通過@property語法來定義對(duì)象中所封裝的數(shù)據(jù)自沧。
- 通過“特質(zhì)”來指定存儲(chǔ)數(shù)據(jù)所需的正確語義(原子性: atomic / nonautomic; 讀寫權(quán)限: readonly/ readwrite; 內(nèi)存管理語義: assign/ strong/week/ unsafe_unretained/copy; 方法名 getter=<methodName>/setter = <methodeName>)
- 在設(shè)置屬性所對(duì)應(yīng)的實(shí)例變量時(shí)坟奥,一定要遵從該屬性所聲明的語義(注意 copy語義)。
- 開發(fā)iOS程序時(shí)拇厢,應(yīng)該使用nonatomic屬性爱谁,因?yàn)閍tomic屬性會(huì)嚴(yán)重影響性能(為保持原子性會(huì)使用同步鎖)。
- 在對(duì)象內(nèi)部盡量直接訪問實(shí)例變量
- 在對(duì)象內(nèi)部讀取數(shù)據(jù)時(shí)孝偎,應(yīng)該直接通過實(shí)例變量來讀访敌,而寫入數(shù)據(jù)時(shí),應(yīng)該通過屬性來寫衣盾。(需要考慮 getter/setter 方法的功能, 如果有業(yè)務(wù)邏輯, 那還是應(yīng)該調(diào)用讀寫方法)
- 在初始化方法及dealloc方法中寺旺,總是應(yīng)該直接通過實(shí)例變量來讀寫數(shù)據(jù)(因?yàn)樽宇惪梢灾貙懽x寫方法, 在初始化過程調(diào)用可能引發(fā)潛在問題)。
- 有時(shí)會(huì)使用惰性初始化技術(shù)配置某份數(shù)據(jù)势决,這種情況下阻塑,需要通過屬性來讀取數(shù)據(jù)。(在 getter 方法中判斷是否已有值, 如果沒有則建對(duì)象, 為實(shí)例賦值)
- 理解“對(duì)象等同性”這一概念
- 若想檢測(cè)對(duì)象的等同性果复,請(qǐng)?zhí)峁癷sEqual:”與hash方法陈莽。
- 相同的對(duì)象必須具有相同的hash碼,但是兩個(gè)hash碼相同的對(duì)象卻未必相同(hash 碼可能會(huì)碰撞)。
- 不要盲目的逐個(gè)監(jiān)測(cè)每條屬性走搁,而是應(yīng)該依照具體需求來制定檢測(cè)方案独柑。
- 編寫hash方法時(shí),應(yīng)該使用計(jì)算速度快而且哈希碼碰撞幾率低的算法私植。
- 以“類族模式”隱藏實(shí)現(xiàn)細(xì)節(jié)
- 類族模式可以把實(shí)現(xiàn)細(xì)節(jié)隱藏在一套簡(jiǎn)單的公共接口后面忌栅。(通過工廠方法創(chuàng)建不同類型子類的實(shí)例)
- 系統(tǒng)框架中經(jīng)常使用類族(UIButton, NSArray…)。
- 從類族的公共抽象基類中繼承子類時(shí)要當(dāng)心曲稼,若有開發(fā)文檔索绪,則應(yīng)首先閱讀。
- 在既有類中贫悄,使用關(guān)聯(lián)對(duì)象(Associated Object)存放自定義數(shù)據(jù)
- 可以通過“關(guān)聯(lián)對(duì)象”機(jī)制來把兩個(gè)對(duì)象連起來, 使用以下方法
//需要引用頭文件: #import <objc/runtime.h>
void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy);
id objc_getAssociatedObject(id object, const void *key);
void objc_removeAssociatedObjects(id object);者春。
- 定義關(guān)聯(lián)對(duì)象時(shí)可指定內(nèi)存管理語義,用以模仿定義屬性時(shí)所采用的“擁有關(guān)系”與“非擁有關(guān)系”清女。
- 只有在其他做法不可行時(shí)才應(yīng)選用關(guān)聯(lián)對(duì)象钱烟,因?yàn)檫@種做法通常會(huì)引入難于查找的bug。
- 理解objc_msgSend的作用
- 消息由接受者嫡丙,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ī)制
- 若對(duì)象無法響應(yīng)某個(gè)selector父泳,則進(jìn)入消息轉(zhuǎn)發(fā)流程般哼。
- 通過運(yùn)行期的動(dòng)態(tài)方法解析功能,我們可以在需要用到某個(gè)方法時(shí)再將其加入類中
(+ (BOOL)resolveInstanceMethod:(SEL)sel;, - 類中加動(dòng)法方法 BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);
)惠窄。 - 對(duì)象可以將其無法解讀的某些selector轉(zhuǎn)交給其他對(duì)象處理(- (id)forwardingTargetForSelector:(SEL)aSelector;)蒸眠。
- 經(jīng)過上述兩步后,如果還是沒辦法處理selector杆融,那就啟動(dòng)完整的消息轉(zhuǎn)發(fā)機(jī)制(- (void)forwardInvocation:(NSInvocation *)anInvocation;)楞卡。
- 用method swizzling調(diào)試黑盒方法
- 在runtime中,可以向類中新增或替換selector所對(duì)應(yīng)的方法實(shí)現(xiàn)(
void method_exchangeImplementations(Method m1, Method m2);)脾歇。 - 使用另一份實(shí)現(xiàn)來替換原有的方法實(shí)現(xiàn)蒋腮,這道工序叫做method swizzling,開發(fā)者常用此技術(shù)向原有視線中添加功能藕各。
- 一般來說池摧,只有調(diào)試程序的時(shí)候才需要在runtime中修改方法實(shí)現(xiàn),這種做法不宜濫用激况。
- 理解“類對(duì)象”的用意
- 每個(gè)實(shí)例都有一個(gè)指向Class對(duì)象的指針作彤,用以表明其類型踢京,而這些Class對(duì)象則構(gòu)成了累的繼承體系。
- 如果對(duì)象類型無法在編譯期確定宦棺,那么就應(yīng)該使用類型信息查詢方法來探知。
- (BOOL)isMemberOfClass:(Class)aClass; //判斷對(duì)象是否為某個(gè)特定類的實(shí)例
- (BOOL)isKindOfClass:(Class)aClass; //判斷對(duì)象是否為某個(gè)特定類或派生類的實(shí)例
- 盡量使用類型信息查詢方法來確定對(duì)象類型黔帕,而不要直接比較類對(duì)象代咸,因?yàn)槟承?duì)象可能實(shí)現(xiàn)了消息轉(zhuǎn)發(fā)功能。