編寫高質(zhì)量iOS與OS X代碼的52個有效方法
一、熟悉Objective-C
1、了解Objective-C語言的起源
* Objective-C為C語言添加了面向?qū)ο筇匦裕瞧涑?。Objective-C使用動態(tài)綁定的消息結(jié)構(gòu),也就是說,在運行時才會檢查對象類型。接收一條消息之后,究竟應(yīng)執(zhí)行何種代碼,由運行期環(huán)境而非編譯器來決定。
* 理解C語言的核心概念有助于寫好Objective-C程序。尤其要掌握內(nèi)存模型與指針。
2、在類的頭文件中盡量少引入其他頭文件
* 除非確有必要,否則不要引入頭文件。一般來說,應(yīng)在某個類的頭文件中使用向前聲明來提及別的類,并在實現(xiàn)文件中引入那些類的頭文件。這樣做可以盡量降低類之間的耦合(coupling)。
* 有時無法使用向前聲明,比如要聲明某個類遵循一項協(xié)議。這種情況下,盡量把“該類遵循某協(xié)議”的這條聲明移至“class-continuation分類”中。如果不行的話,就把協(xié)議單獨放在一個頭文件中,然后將其引入。
3、多用字面量語法,少用與之等價的方法
* 應(yīng)該使用字面量語法來創(chuàng)建字符串、數(shù)值、數(shù)組、字典。與創(chuàng)建此類對象的常規(guī)方法相比,這么做更加簡明扼要。
* 應(yīng)該通過取下標操作來訪問數(shù)組下標或字典中鍵所對應(yīng)的元素。
* 用字面量語法創(chuàng)建數(shù)組或字典時,若值中有nil,則會拋出異常。因此,務(wù)必確保值里不含nil。
4、多用類型常量,少用#define預處理指令
* 不要用預處理指令定義常量。這樣定義出來的常量不含類型信息,編譯器只是會在編譯前據(jù)此執(zhí)行查找與替換操作。即使有人重新定義了常量值,編譯器也不會產(chǎn)生警告信息,這將導致應(yīng)用程序中的常量值不一致。
* 在實現(xiàn)文件中使用static const來定義“只在編譯單元內(nèi)可見的常量”(translation-unit-specific constant)。由于此類常量不在全局符號表中,所以無需為其名稱加前綴。
* 在頭文件中使用extern來聲明全局變量,并在相關(guān)實現(xiàn)文件中定義其值。這種常量要出現(xiàn)在全局符號表中,所以其名稱應(yīng)加以區(qū)隔,通常用與之相關(guān)的類名做前綴。
5、枚舉表示狀態(tài)、選項、狀態(tài)碼
* 應(yīng)該用枚舉來表示狀態(tài)機的狀態(tài)、傳遞給方法的選項以及狀態(tài)碼等值,給這些值起個易懂的名字。
* 如果把傳遞給某個方法的選項表示枚舉類型,而多個選項又可同時使用,那么就將各選項值定義為2的冪,以便通過按位或操作將其組合起來。
* 用NS_ENUM與NS_OPTIONS宏來定義枚舉類型,并指明其底層數(shù)據(jù)類型。這樣做可以確保枚舉是用開發(fā)者所選的底層數(shù)據(jù)類型實現(xiàn)出來的,而不是采用編譯器所選的類型。
* 在處理枚舉類型的switch語句中不要實現(xiàn)default分支。這樣的話,加入新枚舉之后,編譯器就會提示開發(fā)者:switch語句并未處理所有枚舉。
二、對象、消息、運行期
6、理解“屬性”這一概念
* 可用@property語法來定義對象中所封裝的數(shù)據(jù)。
* 通過“特質(zhì)”來指定存儲數(shù)據(jù)所需的正確語義。
* 在設(shè)置屬性所對應(yīng)的實例變量時,一定要遵從該屬性所聲明的語義。
* 開發(fā)iOS程序時應(yīng)該使用nonatomic屬性,因為atomic屬性會嚴重影響性能。
7、在對象內(nèi)部盡量直接訪問實例變量
* 在對象內(nèi)部讀取數(shù)據(jù)時,應(yīng)該直接通過實例變量來讀,而寫入數(shù)據(jù)時,則應(yīng)通過屬性來寫。
* 在初始化方法及dealloc方法中,總是應(yīng)該直接通過實例變量來讀寫數(shù)據(jù)。
* 有時會使用惰性初始化技術(shù)配置某份數(shù)據(jù),這種情況下,需要通過屬性來讀取數(shù)據(jù)。
8、理解“對象等同性”這一概念
* 若想檢測對象的等同性,請?zhí)峁癷sEqual:”與hash方法。
* 相同的對象必須具有相同的哈希碼,但是兩個哈希碼相同的對象未必相同。
* 不要盲目地逐個檢測每個屬性,而是應(yīng)該依照具體需求來制定檢測方案。
* 編寫hash方法時,應(yīng)該使用計算速度而且哈希碼碰撞幾率低的算法。
9、以“類族模式”隱藏實現(xiàn)細節(jié)
* 類族模式可以把實現(xiàn)細節(jié)隱藏在一套簡單的公共接口后面。
* 系統(tǒng)框架中經(jīng)常使用類族。
* 從類族的公共抽象基類中繼承子類時要當心,若有開發(fā)文檔,則應(yīng)首先閱讀。
10、在既有類中使用關(guān)聯(lián)對象存放自定義數(shù)據(jù)
* 可以通過“關(guān)聯(lián)對象”機制來把兩個對象連起來
* 定義關(guān)聯(lián)對象時可指定內(nèi)存管理語義,用以模仿定義屬性時所采用的“擁有關(guān)系”與“非擁有關(guān)系”。
* 只有在其他做法不可行時才應(yīng)選用關(guān)聯(lián)對象,因為這種做法通常會引入難于查找的bug
11、理解 objc_msgSend 的作用
* 消息由接收者、選擇子及參數(shù)構(gòu)成。給某對象“發(fā)送消息”(invoke a message)也就是相當于在該對象上“調(diào)用方法”(call a method)。
* 發(fā)給某對象的全部消息都要由“動態(tài)消息派發(fā)系統(tǒng)”(dynamic message dispatch system)來處理,該系統(tǒng)會查出對應(yīng)的方法,并執(zhí)行其代碼。
12、理解消息轉(zhuǎn)發(fā)機制
* 若對象無法響應(yīng)某個選擇子,則進入消息轉(zhuǎn)發(fā)流程
* 通過運行期的動態(tài)方法解析功能,我們可以在需要用到某個方法時再將其加入類中。
* 對象可以把其無法解讀的某型選擇子轉(zhuǎn)交給其他對象來處理。
* 經(jīng)過上述兩步之后,如果還是沒辦法處理選擇子,那就啟動完整的消息轉(zhuǎn)發(fā)機制
13、用“方法調(diào)配技術(shù)”調(diào)試“黑盒方法”
* 使用另一份實現(xiàn)來替換原有的方法實現(xiàn),這道工序叫做“方法調(diào)配”,開發(fā)者常用此技術(shù)向原有實現(xiàn)中添加新功能。
* 一般來說,只有調(diào)試程序的時候才需要在運行期修改方法實現(xiàn),這種做法不宜濫用。
14、理解“類對象”的用意
* 每個實例都有一個指向 Class 對象的的指針,用以表明其類型,而這些 Class 對象則構(gòu)成了類的繼承體系
* 如果對象類型無法在編譯期確定,那么就應(yīng)該使用類型信息查詢方法來探知。
* 盡量使用類型信息查詢方法來確定對象類型,而不要直接比較對象,因為某些對象可能實現(xiàn)了消息轉(zhuǎn)發(fā)功能
三、接口與API設(shè)計
15、用前綴避免命名空間沖突
* 選擇與你的公司、應(yīng)用程序或二者皆有關(guān)聯(lián)之名稱作為類名的前綴,并在所有代碼中均使用這一前綴
* 若自己所開發(fā)的程序中用到了第三方庫,則應(yīng)為其中的名稱加上前綴。
16、提供“全能初始化方法”
* 在類中提供一個全能初始化方法,并于文檔里指明。其他初始化方法均應(yīng)用調(diào)用此方法。
* 若全能初始化方法與超類不同,則需覆寫超類中的對應(yīng)方法
* 如果超類的初始化方法不適用于子類,那么應(yīng)該覆寫這個超類方法,并在其中拋出異常
17、實現(xiàn) description 方法
* 實現(xiàn) description 方法返回一個有意義的字符串,用以描述該實例
* 若想在調(diào)試時打印出更詳盡的對象描述信息,則應(yīng)實現(xiàn) debugDescription 方法
18、盡量使用不可變對象
* 盡量創(chuàng)建不可變的對象
* 若某屬性僅可于對象內(nèi)部修改,則在“class-continuation 分類”中將其由 readonly 屬性擴展為 readwrite 屬性。
* 不要把可變的 collection 作為屬性公開,而應(yīng)提供相關(guān)方法,以此修改對象中的可變 collection。
19、使用清晰而協(xié)調(diào)的命名方式
* 起名時應(yīng)遵從標準的 Objective-C 命名規(guī)范,這樣創(chuàng)建出來的接口更容易為開發(fā)者所理解。
* 方法名要言簡意賅,從左至右讀起來要像個日常用語中的句子才好
* 方法名里不要使用縮略后的類型名稱
* 給方法起名時的第一要務(wù)就是確保其風格與你自己的代碼或所要集成的框架相符。
20、為私有方法名加前綴
* 給私有方法的名稱加上前綴,這樣可以很容易將其同公共方法區(qū)分開。
* 不要單用一個下劃線做私有方法的前綴,因為這種做法是預留給蘋果公司用的。
21、理解 Objective-C 錯誤模型
* 只有發(fā)生了可使整個應(yīng)用程序崩潰的嚴重錯誤時,才應(yīng)使用異常。
* 在錯誤不那么嚴重的情況下,可以指派“委托方法”(delegate method)來處理錯誤,也可以把錯誤信息放在 NSEorror 對象里,經(jīng)由“輸出參數(shù)”返回給調(diào)用者。
22、理解 NSCopying 協(xié)議
*? 若想令自己所寫的對象具有拷貝功能,則需要實現(xiàn) NSCopying 協(xié)議。
* 如果自定義的對象分為可變版本與不可變版本,那么就要同時實現(xiàn) NSCopying 與 NSMutableCopying 協(xié)議。
* 復制對象時需要決定采用淺拷貝還是深拷貝,一般情況下應(yīng)該盡量執(zhí)行淺拷貝。
* 如果你所寫的對象需要深拷貝,那么可以考慮新增一個專門執(zhí)行深拷貝的方法。
四、協(xié)議與分類
23、通過委托與數(shù)據(jù)源協(xié)議進行對象間通信
* 將委托對象應(yīng)該支持的接口定義成協(xié)議,在協(xié)議中把可能需要處理的事件定義成方法。
* 當某對象需要另外一個對象中獲取數(shù)據(jù)時,可以使用委托模式。這種情境下,該模式亦稱“數(shù)據(jù)源協(xié)議”(data source protocal)
* 若有必要,可實現(xiàn)含有段位的結(jié)構(gòu)體,將委托對象是否能響應(yīng)相關(guān)協(xié)議方法這一信息緩存至其中
24、將類的實現(xiàn)代碼分散到便于管理的數(shù)個分類之中
* 使用分類機制把類的實現(xiàn)代碼劃分成易于管理的小塊
* 將應(yīng)該視為“私有”的方法歸入名叫 Private 分類中,以隱藏實現(xiàn)細節(jié)
25、總是為第三方類的分類名稱加前綴
* 向第三方類中添加分類時,總應(yīng)給其名稱加上你的專用的前綴
* 向第三方類中添加分類時,總應(yīng)給其中的方法名加上你專用的前綴
26、勿在分類匯總聲明屬性
* 把封裝數(shù)據(jù)所用的全部屬性都定義在主接口里
* 在“class-continuation 分類”之外的其他分類中,可以定義存取方法,但盡量不要定義屬性
27、使用“class-continuation 分類”隱藏實現(xiàn)細節(jié)
* 通過“class-continuation 分類”向類中新增實例變量。
* 如果某屬性在主接口中聲明為“只讀”,而類的內(nèi)部又要用設(shè)置方法修改此屬性,那么就在“class-continuation 分類”中將其擴展為“可讀寫”。
* 把私有方法的原型聲明在“class-continuation 分類”里面。
* 若想使類所遵循的協(xié)議不為所知,則可于“class-continuation 分類”中聲明。
28、通過協(xié)議提供匿名對象
* 協(xié)議可在某種程度上提供匿名類型。具體的對象類型可以淡化稱遵從某協(xié)議的 id 類型,協(xié)議里規(guī)定了對象所應(yīng)實現(xiàn)的方法。
* 使用匿名對象來隱藏類型名稱(或類名)。
* 如果具體類型不重要,重要的是對象能夠響應(yīng)(定義在協(xié)議里的)特定方法,那么可使用匿名對象來表示。
五、內(nèi)存管理
29、理解引用計數(shù)
* 引用計數(shù)機制可以遞增遞減的計數(shù)器來管理內(nèi)存。對象創(chuàng)建好之后,其保留計數(shù)至少為1。若保留計數(shù)為正,則對象繼續(xù)存活。當保留計數(shù)降為0時,對象就被銷毀了。
* 在對象生命期中,其余對象通過引用來保留或釋放此對象。保留與釋放操作分別會遞增及遞減保留計數(shù)。
30、以 ARC 簡化引用計數(shù)
* 在 ARC 之后,程序員就無須擔心內(nèi)存管理問題了。使用 ARC 來編程,可省去類中的許多“樣板代碼”。
* ARC 管理對象生命期的辦法基本上就是:在合適的地方插入“保留”及“釋放”操作。在 ARC 環(huán)境下,變量的內(nèi)存管理語義可以通過修飾符指明,而原來則需要手工執(zhí)行“保留”及“釋放”操作。
* 由方法所返回的對象,其內(nèi)存管理語義總是通過方法名來體現(xiàn)。ARC 將此確定為開發(fā)者必須遵循的規(guī)則。
* ARC 只負責管理 Objective-C 對象的內(nèi)存。尤其要注意:CoreFoundation 對象不歸 ARC 管理,開發(fā)者必須適時調(diào)用 CFRetain/CFRelease。
31、在dealloc 方法中只釋放引用并解除監(jiān)聽
* 在dealloc方法里,應(yīng)該做的事情就是釋放指向其他對象的引用,并取消原來訂閱的“鍵值觀測”(KVO)或 NSNotificationCenter 等通知,不要做其他事情。
* 如果對象持有文件描述符等系統(tǒng)資源,那么應(yīng)該專門編寫一個方法來釋放此種資源。這樣的類要和其使用者約定:用完資源后必須調(diào)用 close 方法。
* 執(zhí)行異步任務(wù)的方法不應(yīng)在dealloc 里調(diào)用;只能在正常狀態(tài)下執(zhí)行的那些方法也不應(yīng)在dealloc 里調(diào)用。
32、編寫“異步安全代碼”時留意內(nèi)存管理問題
* 捕獲異常時,一定要注意將 try 塊內(nèi)所創(chuàng)立的對象清理干凈。
* 在默認情況下,ARC 不生成安全處理異常所需要的清理代碼。開啟編譯器標志后,可生成這種代碼,不過會導致應(yīng)用程序變大,而且會降低運行效率。
33、以弱引用避免保留環(huán)
* 將某些引用設(shè)為 weak,可避免出現(xiàn)“保留環(huán)”。
* weak 引用可以自動清空,也可以不自動清空。自動清空(autonilling)是隨著 ARC 而引入的新特性,由運行期系統(tǒng)來實現(xiàn)。在具備自動清空功能的弱引用上,可以隨意讀取其數(shù)據(jù),因為這種引用不會指向已經(jīng)回收過的對象。
34、以“自動釋放池”降低內(nèi)存峰值
* 自動釋放池排布在棧中,對象收到 autorelease 消息后,系統(tǒng)將其放入最頂端的池里。
* 合理運用自動釋放池,可降低應(yīng)用程序的內(nèi)存峰值。
* @autoreleasepool 這種新式寫法能創(chuàng)建出更為輕便的自動釋放池。
35、用“僵尸對象”調(diào)試內(nèi)存管理問題
* 系統(tǒng)在回收對象時,可以不將其真的回收,而是把它轉(zhuǎn)化為僵尸對象。通過環(huán)境變量 NSZombieEnable 可開啟此功能。
* 系統(tǒng)會修改對象的 isa 指針,令其指向特殊的僵尸類,從而使該對象變?yōu)榻┦瑢ο?。僵尸類能夠響?yīng)所有的選擇子,響應(yīng)方式為:打印一條包含消息內(nèi)容及其接收者的消息,然后終止應(yīng)用程序。
36、不要使用 retainCount
* 對象的把保留計數(shù)看似有用,實則不然,因為任何給定時間上的“絕對保留計數(shù)”(absolute retain count)都無法反映對象生命期的全貌。
* 引入 ARC 之后,retainCount 方法就正式廢止了,在 ARC 下調(diào)用該方法會導致編譯器報錯。
六、塊與大中樞派發(fā)
37、理解“塊”這一概念
* 塊是 C、C++、Objective-C 中的詞法閉包
* 塊可接受參數(shù),也可返回值。
* 塊可以分配在?;蚨焉希部梢允侨值?。分配在棧上的塊可拷貝到堆里,這樣的話,就和標準的 Objective-C 對象一樣,具備引用計數(shù)了。
38、為常用的塊類型創(chuàng)建 typedef
* 以 typedef 重新定義塊類型,可令變量用起來更加簡潔。
* 定義新類型時應(yīng)遵從現(xiàn)有的命名習慣,勿使用其名稱與別的類型相沖突。
* 不妨為同一個塊簽名定義多個類型別名。如果要重構(gòu)的代碼使用了塊類型的某個別稱,那么只需修改相應(yīng) typedef 中的塊標簽名即可,無須改動其他 typedef。
39、用 handler 塊降低代碼分散程度
* 在創(chuàng)建對象時,可以使用內(nèi)聯(lián)的 handler 塊將相關(guān)業(yè)務(wù)邏輯一并聲明。
* 在有多個實例需要監(jiān)控時,如果采用委托模式,那么經(jīng)常需要根據(jù)傳入的對象來切換,而若改用 handler 塊來實現(xiàn),則可直接將塊與相關(guān)對象放在一起。
* 設(shè)計 API 時如果用到了 handler 塊,那么可以增加一個參數(shù),使調(diào)用者可通過此參數(shù)來決定應(yīng)該把塊安排在哪個隊列上執(zhí)行。
40、用塊引用其所屬對象時不要出現(xiàn)保留環(huán)
* 如果塊所捕捉的對象直接或間接地保留了塊的本身,那么就得當心保留環(huán)問題。
* 一定要找個適當?shù)臅r機解除保留環(huán),而不能把責任推給 API 的調(diào)用者。
41、多用派發(fā)隊列,少用同步鎖
* 派發(fā)隊列可用來表述同步語義(synchronization semantic),這種做法要比使用@synchronized 塊或NSLock 對象更簡單。
* 將同步與異步派發(fā)結(jié)合起來,可以實現(xiàn)與普通加鎖機制一樣的同步行為,而這么做卻不會阻塞執(zhí)行異步派發(fā)的線程。
* 使用同步隊列及柵欄塊,可以令同步行為更加高效。
42、多用 GCD,少用 performSelector 系列方法
* performSelector 系列方法在內(nèi)存管理方面容易有疏失。它無法確定將要執(zhí)行的選擇子具體是什么,因而 ARC 編譯器也就無法插入適當?shù)膬?nèi)存管理方法。
* performSelector 系列方法所能處理的選擇子太過局限了,選擇子的返回值類型及發(fā)送給方法的參數(shù)個數(shù)都受到限制。
* 如果想把任務(wù)放在另一個線程上執(zhí)行,那么最好不要用 performSelector 系列方法,而是應(yīng)該把任務(wù)封裝到這里然后調(diào)用大中樞派發(fā)機制的相關(guān)方法來實現(xiàn)。
43、掌握 GCD 及操作隊列的使用時機
* 在解決多線程與任務(wù)管理問題時派發(fā)隊列并非唯一方案
* 操作隊列提供了一套高層的 Objective-C API,能實現(xiàn)純 GCD 所具備的絕大部分功能,而且還能完成一些更為復雜的操作,那些操作若改用 GCD 來實現(xiàn),則需要另外編寫代碼。
44、通過 Dispatch Croup 機制,根據(jù)系統(tǒng)資源狀態(tài)來執(zhí)行任務(wù)
* 一系列任務(wù)可歸入一個 dispatch group 之中,開發(fā)者可以在這組任務(wù)執(zhí)行完畢時獲得通知。
* 通過dispatch group,可以在并發(fā)式派發(fā)隊列里同時執(zhí)行多項任務(wù)。此時 GCD 會根據(jù)系統(tǒng)資源狀況來調(diào)度這些并發(fā)執(zhí)行的任務(wù)。開發(fā)者若自己來實現(xiàn)此功能,則需要編寫大量代碼。
45、使用 dispatch_once 來執(zhí)行只需運行一次的線程安全代碼
* 經(jīng)常需要編寫“只需執(zhí)行一次的線程安全代碼”(thread-safe single-code execution)。通過 GCD 所提供的 dispatch_once 函數(shù),很容易就能實現(xiàn)此功能。
* 標記應(yīng)該聲明在 static 或 global 作用域中,這樣的話,在把只需執(zhí)行一次的塊傳給 dispatch_once 函數(shù)時,傳進去的標記也是相同的。
46、不要使用 dispatch_get_current_queue
* dispatch_get_current_queue 函數(shù)的行為常常與開發(fā)者所預期的不同。此函數(shù)已經(jīng)廢棄,只應(yīng)做調(diào)試之用。
* 由于派發(fā)隊列示按層級來組織的,所以無法單用某個隊列對象來描述“當前隊列”這一概念。
* dispatch_get_current_queue 函數(shù)用于解決由不可重入的代碼所引發(fā)的死鎖,然而能用此函數(shù)解決的問題,通常也能改用“隊列特定數(shù)據(jù)”來解決。
七、系統(tǒng)框架
47、熟悉系統(tǒng)框架
* 許多系統(tǒng)框架都可以直接使用。其中最重要的是 Foundation 與 CoreFoundation,這兩個框架提供了構(gòu)建應(yīng)用程序所需的許多核心功能。
* 很多常見任務(wù)都能用框架來做,例如音頻與視頻處理、網(wǎng)絡(luò)通信、數(shù)據(jù)管理等。
* 請記住:用純 C 寫成的框架與用 Objective-C 寫成的一樣重要,若想成為優(yōu)秀的 Objective-C開發(fā)者,應(yīng)該掌握 C 語言的核心概念。
48、多用塊枚舉,少用 for 循環(huán)
* 遍歷 collection 有四種方式。最基本的辦法是 for 循環(huán),其次是 NSEnumerator 遍歷法及快速遍歷法,最新、最先進的方式則是“塊枚舉法”。
* “塊枚舉法”本身就能通過 GCD 來并發(fā)執(zhí)行遍歷操作,無須另行編寫代碼。而采用其他遍歷方式則無法輕易實現(xiàn)這一點。
* 若提前知道待遍歷的 collection 含有何種對象,則應(yīng)修改塊簽名,指出對象的具體類型。
49、對自定義其內(nèi)存管理語義的 collection 使用無縫橋接
* 通過無縫橋接技術(shù),可以在 Foundation 框架中的 Objective-C 對象與 CoreFoundation 框架中的 C 語言數(shù)據(jù)結(jié)構(gòu)之間來回轉(zhuǎn)換。
* 在 CoreFoundation 層面創(chuàng)建 collection 時,可以指定許多回調(diào)函數(shù),這些函數(shù)表示此 collection 應(yīng)如何處理其元素。然后,可運用無縫橋接技術(shù),將其轉(zhuǎn)換成具備特殊內(nèi)存管理語義的 Objective-C collection。
50、構(gòu)建緩存時選用 NSCache 而非 NSDictionary
* 實現(xiàn)緩存時應(yīng)選用 NSCache 而非 NSDictionary 對象。因為 NSCache 可以提供優(yōu)雅自動刪減功能,而且是“線程安全的”,此外,它與字典不同,并不會拷貝鍵。
* 可以給 NSCache 對象設(shè)置上限,用以限制緩存中的對象總個數(shù)及“總成本”,而這些尺度則定義了緩存刪減其中對象的時機。但是絕對不要把這些尺度當成可靠的“硬限制”(hard limit),它們僅對 NSCache 起指導作用。
* 將 NSPurgeableData 與 NSCache 搭配使用,可實現(xiàn)自動清除數(shù)據(jù)的功能,也就是說,當 NSPurgeableData 對象所占內(nèi)存為系統(tǒng)所丟棄時,該對象自身也會從緩存中移除。
* 如果緩存使用得當,那么應(yīng)用程序的響應(yīng)速度就能提高。只有那種“重新計算起來很費事的”數(shù)據(jù),才值得放入緩存,比如那些需要從網(wǎng)絡(luò)獲取或從磁盤讀取的數(shù)據(jù)。
51、精簡 initialize 與 load 的實現(xiàn)代碼
* 在加載階段,如果類實現(xiàn)了 load 方法,那么系統(tǒng)就會調(diào)用它。分類里也可以定義此方法,類的 load 方法要比分類中的先調(diào)用。與其他方法不同,load 方法不參與覆寫機制。
* 首次使用某個類之前,系統(tǒng)會向其發(fā)送 initialize 消息。由于此方法遵從普通的覆寫規(guī)則,所以通常應(yīng)該在里面判斷當前要初始化的是哪個類。
* load 與 initialize 方法都應(yīng)該實現(xiàn)得精簡一些,這有助于保持應(yīng)用程序的響應(yīng)能力,也能減少引入“依賴環(huán)”(interdependecy cycle)的幾率。
* 無法在編譯其設(shè)定的全局常量,可以放在initialize 方法里初始化。
52、別忘了 NSTimer 會保留其目標對象
* NSTimer 對象會保留其目標,直到計時器本身失效為止,調(diào)用 invalidate 方法可令計時器失效,另外,一次性的計時器在觸發(fā)完任務(wù)之后也會失效。
* 反復執(zhí)行任務(wù)的計時器(repeating timer),很容易引入保留環(huán),如果這種計時器的目標對象又保留了計時器本身,那肯定會導致保留環(huán)。這種環(huán)狀保留關(guān)系,可能是直接發(fā)生的,也可能是通過對象圖里的其他對象間接發(fā)生的。
* 可以擴充 NSTimer 的功能,用“塊”來打破保留環(huán)。不過,除非 NSTimer 將來在公共接口里提供此功能,否則必須創(chuàng)建分類,將相關(guān)實現(xiàn)代碼加入其中。