第2條:在類的頭文件中盡量少引入其他頭文件塔粒。
- 減少編譯時間?
- 解決兩個類互相引用 造成無法正確編譯的問題糖声。
第4條:多用類型常量 static const抽莱,少用#define預(yù)處理指令。
用預(yù)處理定義的常量不含類型信息纸型,且編譯器只會在編譯前據(jù)此執(zhí)行查找和替換操作拇砰。
第5條:用枚舉表示狀態(tài)、選項狰腌、狀態(tài)碼
- 用枚舉表示狀態(tài)除破、選項、狀態(tài)碼琼腔,可以向后兼容皂岔,用typedef NS_ENUM 和?typedef NS_OPTIONS區(qū)分開來。
- C++模式下typedef NS_ENUM編譯展姐,會認(rèn)為數(shù)據(jù)結(jié)果是NSInteger,不能將底層類型“隱式轉(zhuǎn)換”為枚舉類型本身剖毯,只能顯示轉(zhuǎn)換才不會報錯圾笨。所以,凡是按位或操作來組合枚舉都應(yīng)該使用NS_OPTIONS定義逊谋。
- 枚舉在switch中最好不要用default擂达,這樣枚舉新增狀態(tài)時,這個switch就會發(fā)出警告胶滋。
第6條:理解屬性的概念
- @dynamic能阻止編譯器自動合成存取方法
- 當(dāng)屬性類型為NSString * 時板鬓,經(jīng)常用此特質(zhì)來保護(hù)其封裝性。因為傳遞給設(shè)置方法的新值可能是mutable究恤,這時不copy俭令,可能就會被在對象不知情的情況下遭人更改。
第7條:在對象內(nèi)部盡量直接訪問實例變量
- 在對象內(nèi)部讀取實例變量時采用直接訪問的方式部宿,設(shè)置實例變量的時候通過屬性去做
- 在init 和dealloc 方法中抄腔,總是應(yīng)該直接通過實例變量來讀寫數(shù)據(jù)
第10條:在既有類中使用關(guān)聯(lián)對象存放自定義數(shù)據(jù)
void objc_setAssociatedObject (id object, void *key, id value, objc_AssociationPolicy policy)
id?objc_getAssociatedObject?(id object, void *key)
void objc_removeAssociatedObjects (id object)?
和NSDictionary 類似瓢湃,但關(guān)聯(lián)對象的key是不透明指針,如果想要兩個key匹配到同一value赫蛇,二者必須完全相同的指針绵患。鑒于此,在設(shè)置關(guān)聯(lián)對象值時悟耘,通常使用靜態(tài)全局變量作為key落蝙。
其他做法不可行時才應(yīng)使用關(guān)聯(lián)對象,因為使用關(guān)聯(lián)對象很難找出bug
第11條:理解objc_msgSend的作用
- 在調(diào)用該對象中的某個方法暂幼,但這個方法未被定義的情況下筏勒,我們可以通過消息轉(zhuǎn)發(fā)機制來解決
- objc是一門運行時語言,每個方法都會在運行時被動態(tài)的轉(zhuǎn)為objc_msgSend(receiver, selector, parameter)
- objc_msgSend 會將匹配結(jié)果緩存在快速映射表fast map里粟誓,每一個類都有這樣一塊緩存奏寨,指針都會指向這種函數(shù),@selector方法名則是查表的key
第12條:理解消息轉(zhuǎn)發(fā)機制
在objc向一個對象發(fā)送消息時鹰服,runtime會根據(jù)對象的isa指針去找到該對象實屬的類病瞳,然后在類中去尋找selector,若該類沒有悲酷,便往上一層層尋找套菜。到最頂層的父類依然沒有這個方法的話,程序就會給出三次拯救程序crash的機會:
動態(tài)方法解析
1)通過運行期的動態(tài)方法解析功能设易,+resolveInstanceMethod:或者?+resolveClassMethod:?讓你有機會提供一個函數(shù)實現(xiàn)逗柴,使用該辦法的前提是:相關(guān)方法的實現(xiàn)代碼已經(jīng)寫好,只等著運行時動態(tài)插在類里面即可顿肺。如果你添加了函數(shù)戏溺,運行時系統(tǒng)便會重新啟動一次發(fā)送消息的過程。否則屠尊,下一步旷祸。
備援接受者
2)-forwardingTargetForSelector:??如果目標(biāo)對象實現(xiàn)了這個方法,runtime就會提供將這個消息轉(zhuǎn)發(fā)給其它對象的機會讼昆。通過此方案托享,我們可以用組合來模擬出多繼承。只要你返回的不是nil或者self浸赫,整個消息發(fā)送的過程就會被重啟闰围,發(fā)送的對象會變成你返回的那個對象。否則既峡,下一步羡榴。
完整的消息轉(zhuǎn)發(fā)
3)創(chuàng)建NSInvocation,調(diào)用 -forwardInvocation:(NSInvocation *)invocation 运敢,objc會發(fā)送?-methodSignatureForSelector:?消息獲取函數(shù)的參數(shù)和返回類型炕矮,如果返回nil么夫,runtime則會發(fā)送一條?-doesNotRecognizeSelector:?消息,然后crash肤视。如果返回一個函數(shù)簽名档痪,runtime就會創(chuàng)建一個NSInvocation對象并發(fā)送?-forwardInvocation:給目標(biāo)對象。
第13條:用“方法調(diào)配技術(shù)”調(diào)試“黑盒方法”
交換方法函數(shù):method_exchangeImplementations(Method m1, Method m2)
獲得方法實現(xiàn):Method ?class_getInstanceMethod (Class aClass, SEL aSelector)
可以編寫一個新方法邢滑,在此方法中實現(xiàn)所需的附加功能腐螟,并調(diào)用原有實現(xiàn)。
第14條:理解“類對象”的用意
id和NSObject的區(qū)別在于困后,發(fā)送一個消息乐纸,NSObject若無法解讀,編譯器則會產(chǎn)生警告信息摇予,id類型會相應(yīng)所有類型的消息
盡量使用類型信息查詢方法來確定對象類型汽绢,而不要直接比較類對象,因為某些對象可能實現(xiàn)了消息轉(zhuǎn)發(fā)功能