理解“塊”這一概念
要點
- 塊是C担平、C++示绊、Objective-C中的詞法閉包
- 塊可以接受參數(shù)、也可返回值
- 塊可以分配在椩萋郏或堆上,也可以是全局的拌禾。分配在棧上的塊可以拷貝到堆里取胎,這樣的話,就和標準的Objective-C對象是一樣的湃窍,具備引用計數(shù)了
關(guān)于塊原理的說闻蛀,可以參加我的文章說說Objective-C中的block
為常用的塊類型創(chuàng)建typedef
要點
- 以typedef重新定義塊類型,可令塊變量用起來更加簡單
- 定義新類型時應遵循現(xiàn)有的命名習慣您市,勿使用其名稱與別的類型沖突
注:用當前類名最為block的前綴名觉痛,防止block名沖突 - 不妨為同一個塊簽名定義多個類別名。如果要重構(gòu)的代碼使用了塊類型的某個別名茵休,那么只需要修改相應的typedef中的塊簽名即可薪棒,無需改動其他typedef
注:雖然block內(nèi)容相同手蝎,但是為了以后方便修改坛芽,根據(jù)用途分散block胁艰,用不同的別名
用handler塊降低代碼分散程度
要點
- 在創(chuàng)建對象時兔毙,可以使用內(nèi)聯(lián)的handler塊將相關(guān)業(yè)務邏輯一并聲明
注:相當于使用AFNetworking的block回調(diào) - 在有多個實例需要監(jiān)控時徙邻,如果采用委托模式帅矗,那么經(jīng)常需要根據(jù)傳入的對象來切換鹅巍,而若改用handler塊來實現(xiàn)臀突,則可直接將塊與相關(guān)對象放在一起
注:相當于以前使用ASHttpRequest時港谊,如果一個UIController中使用ASI發(fā)了多個請求贸营,則需要在其請求回調(diào)中吨述,根據(jù)請求的tag來區(qū)分請求,這樣請求回調(diào)代理里就會隨著請求的增多變得愈發(fā)混亂 - 設計API時钞脂,如果用到了handler塊锐极,那么可以增加一個參數(shù),使調(diào)用者可通過此參數(shù)來決定應該把塊安排在哪個隊列上執(zhí)行
用塊引用其所屬對象時不要出現(xiàn)循環(huán)引用
要點
- 如果塊所捕獲的對象直接或者間接地保留了塊本身芳肌,那么就得當心循環(huán)引用問題
- 一定要找個適當?shù)臅r機接觸循環(huán)引用灵再,而不能把責任推給API的調(diào)用者。
注:如可以使用以下代碼亿笤,回調(diào)結(jié)束后翎迁,強制將completionHandler屬性清理干凈。
- (void)p_requestCompleted {
if (_completionHandler) {
_completionHandler(_downloadedData);
}
self.completionHandler = nil;
}
關(guān)于block循環(huán)引用的問題净薛,可見iOS中block的循環(huán)引用問題
多用派發(fā)隊列汪榔,少用同步鎖
要點
- 派發(fā)隊列可用來表述同步語義,這種做法要比使用@synchronized塊或者NSLock對象更簡單
- 將同步與異步派發(fā)結(jié)合起來肃拜,可用實現(xiàn)與普通加鎖機制一樣的同步行為痴腌,而這么做卻不會阻塞執(zhí)行異步派發(fā)的線程
- 使用同步隊列以及柵欄塊,可用令同步行為更加高效燃领。
關(guān)于同步問題士聪,可以參加我文檔文章更高效的同步鎖-GCD 同步鎖
多用GCD,少用performSelector系列方法
要點
- performSelector系列方法在內(nèi)存管理方面容易有疏失猛蔽。它無法確定將要執(zhí)行的選擇子具體是什么剥悟,因而ARC編譯器也就無法插入適當?shù)膬?nèi)存管理方法
注:,如下代碼ARC編譯器就無法插入適當?shù)膬?nèi)存管理方法
SEL selector;
if (/* some condition*/) {
selector = @selector(foo);
} else if (/* some other condition */) {
selector = @selector(bar);
} else {
selector = @selector(baz);
}
id ret = [object performSelector:selector];```
* performSeletor系列方法所能處理的選擇子太過局限了曼库,選擇子的返回值類型以及發(fā)送給方法的參數(shù)個數(shù)受到限制
* 如果想把任務放在另一個線程上執(zhí)行区岗,那么最好不要用perfomSelector系列方法,而是應該把任務封裝到塊里毁枯,然后調(diào)用GCD相關(guān)的方法來實現(xiàn)
**注:**perfomSelector沒辦法指定執(zhí)行的線程
####掌握GCD以及操作隊列的使用時機
#####要點:
* 在解決多線程與任務管理問題時慈缔,派發(fā)隊列并非唯一解決方案
* 操作隊列提供了一套高層的Objective-C API,能實現(xiàn)純GCD所具備的絕大多數(shù)部分功能种玛,而且還能完成一些更為復雜的操作藐鹤,那些操作若改用GCD來實現(xiàn)瓤檐,則需要另外編寫代碼
**針對于NSOperation,可以參見[iOS多線程之NSOperationQueue](http://www.reibang.com/p/52fe1b85c404)**
####通過Dipatch Group機制教藻,根據(jù)系統(tǒng)資源狀況來執(zhí)行任務
#####要點
* 一系列任務可歸入一個dispathc group之中距帅。開發(fā)者可用在這組任務執(zhí)行完畢時獲得通知
* 通過disaptch group,可以在并發(fā)式派發(fā)隊列里同時執(zhí)行多項任務括堤。此時GCD會根據(jù)系統(tǒng)資源狀況來調(diào)度這些并發(fā)執(zhí)行的任務碌秸。開發(fā)者若自己實現(xiàn)此功能,則需要編寫大量代碼
**關(guān)于dispatch group的詳細說明悄窃,
可以參照[[iOS 多線程GCD之dispatch_group](http://www.reibang.com/p/6faea7ef35bc)](http://www.reibang.com/p/6faea7ef35bc)**
####使用dispatch_once來執(zhí)行只需運行一次的線程安全代碼
#####要點
* 經(jīng)常需要編寫”只需要執(zhí)行一次的線程安全代碼“讥电,通過GCD所提供的dispatch_once函數(shù),很容易就能實現(xiàn)此功能
**注:**diapatch_once最常用于單例的創(chuàng)建
* 標記應該聲明static或global作用域轧抗,這樣的話恩敌,在把只需要執(zhí)行一次dispatch_once函數(shù)時,傳進去的標記也是相同的
**注:**使用static是因為每次調(diào)用時都必須使用完全相同的標記横媚,如果不使用static或者global纠炮,那就達不到只執(zhí)行一次的效果了
####不要使用diaptch_get_current_queue
#####要點
* dispatch_get_current_queue函數(shù)的行為常常與開發(fā)者所預期的不同。此函數(shù)已經(jīng)廢棄灯蝴,只應做調(diào)試只用恢口。
* 由于派發(fā)隊列是按層級來組織的,所以無法單用某個隊列隊形來描述“當前隊列”這一概念
* dispatch_get_current_queue函數(shù)用于解決由不可重入的代碼所引起的死鎖穷躁,然而能用此函數(shù)解決的問題耕肩,通常也能用“隊列特定數(shù)據(jù)”來解決
**關(guān)于diaptch_get_current_queue,之后會有專門的文章進行講解**