級別: ★★☆☆☆
標籤:「iOS」「GCD」「Objective-C」
作者: MrLiuQ
審校: QiShare團隊
前言:
這幾篇文章是小編在鑽研《Effective Objective-C 2.0》的知識產出,其中包含作者和小編的觀點,以及小編整理的一些demo。希望能幫助大家以簡潔的文字快速領悟原作者的精華。
在這裡,QiShare團隊向原作者Matt Galloway表達誠摯的敬意。
文章目錄如下:
iOS 編寫高質量Objective-C程式碼(一)
iOS 編寫高質量Objective-C程式碼(二)
iOS 編寫高質量Objective-C程式碼(三)
iOS 編寫高質量Objective-C程式碼(四)
iOS 編寫高質量Objective-C程式碼(五)
iOS 編寫高質量Objective-C程式碼(六)
iOS 編寫高質量Objective-C程式碼(七)
iOS 編寫高質量Objective-C程式碼(八)
本篇的主題是iOS中的 “ 大中樞開發 GCD ”。
先簡單介紹一下今天的主角:GCD
。
- GCD(
Grand Central Dispatch
):一種與塊相關的技術,提供了對執行緒的抽象管理(基於派發佇列dispatch queue
)。GCD會根據系統資源情況,適時且高效地 “建立執行緒” 、“複用執行緒” 、 “銷燬執行緒”。
一、多用派發佇列,少用同步鎖
問:在iOS開發中,如何通過鎖來提供同步機制?(以前面試中,經常問道的問題..)
答:在GCD出現之前,有兩種方式:
- 同步塊:
@synchronized(self) {...}
- (void)synchronizedMethod {
@synchronized (self) {
// Safe area...
}
}
複製程式碼
- NSLock:
[_lock lock];
&[_lock unlock];
_lock = [[NSLock alloc] init];
- (void)synchronizedMethod {
[_lock lock];
// Safe area..
[_lock unlock];
}
複製程式碼
不過這兩種寫法效率很低,如果有很多屬性,那麼每個屬性的同步塊都要等其他同步塊執行完畢才能執行。
GCD出現後,GCD與Block相結合,使開發變得更加簡單、高效。
問:如何保證屬性讀寫時執行緒絕對安全?
答:在屬性寫入時,使用柵欄塊barrier
。只有當前所有併發塊都執行完畢後,才會執行barrier
塊,然後才會繼續向下處理。
- 思路如下:
- 程式碼如下:
_syncQueue = dispatch_queue_create("syncQueue", DISPATCH_QUEUE_CONCURRENT);
//! 讀取字串
- (NSString *)someString {
__block NSString *localSomeString;
dispatch_sync(_syncQueue, ^{
localSomeString = _someString;
});
return localSomeString;
}
- (void)setSomeString:(NSString *)someString {
dispatch_barrier_async(_syncQueue, ^{
_someString = someString;
});
}
複製程式碼
二、多用GCD,少用performSelector系列方法
performSelector
系列方法的缺點有兩個:
performSelector
系列方法可能引起記憶體洩漏: 在ARC環境下,編譯器並不知道將要呼叫的選擇子是什麼,有沒有返回值,返回值是什麼,所以ARC不能判斷返回值是否能釋放,因此ARC做了一個比較謹慎的做法:只新增retain
,不新增release
。因此在有返回值或引數的時候可能導致記憶體洩漏。performSelector
系列方法的返回值只能是void或OC物件型別。performSelector
系列方法最多隻能傳入兩個引數。
因此可以使用GCD來代替performSelector
系列方法:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//do something..
});
複製程式碼
三、掌握GCD及操作佇列的使用時機
GCD
效能很棒,但在執行後臺任務時,GCD
並不一定是最佳選擇。在iOS開發中,還有一種技術叫NSOperationQueue
。GCD
是基於C語言的API,效能較高。而NSOperationQueue
是基於GCD
的抽象。
使用NSOperation
和NSOperationQueue
的優點:
-
支援取消某個
NSOperation
: 在執行任務前,可以在NSOperation物件上呼叫cancel方法,用以表明此任務不需要執行。不過已經啟動的任務無法取消。iOS 8之前,GCD佇列是無法取消的,GCD是“安排好之後就不管了(fire and forget)”。iOS 8之後,支援dispatch_cancel
和dispatch_block_cancel
; -
NSOperation
支援多工操作的依賴關係: 比如:任務A、B、C必須在任務D完成後執行。 -
支援通過
KVO
監控NSOperation
物件的屬性: 例如:可以通過isCancelled
屬性來判斷任務是否已取消,通過isFinished
屬性來判斷任務是否已經完成等等; -
支援指定
NSOperationQueue
的優先順序: 操作的優先順序表示此操作與佇列中其他操作之間的優先關係,優先順序高的NSOperationQueue
先執行,優先順序低的後執行。GCD的佇列也有優先順序,不過不是針對整個佇列的; -
重用
NSOperation
物件: 在開發中你可以使用NSOperation
的子類或者自己建立NSOperation
物件來儲存一些資訊,可以在類中定義方法,使得程式碼能夠多次使用;
四、通過Dispatch Group機制,根據系統資源狀況來執行任務
dispatch group
是GCD
的一項特性,能夠把任務進行分組管理,然後等待這組任務執行完畢時會有通知,開發者可以拿到結果然後繼續下一步操作。
另外,通過dispatch group
在併發佇列上同時執行多項任務的時候,GCD會根據系統資源狀態來幫忙排程這些併發執行的任務。
五、使用dispatch_once來執行只需要執行一次的執行緒安全程式碼
例如:我們開發中寫一個單例,就可以使用dispatch_once
:
+ (instancetype)sharedInstance {
static Class *manager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[Class alloc] init];
});
return manager;
}
複製程式碼
六、不要使用dispatch_get_current_queue
理由如下:
dispatch_get_current_queue
函式的行為常常與開發者所預期的不同,此函式已經廢棄,只應做除錯之用。- 由於
GCD
是按層級來組織的,所以無法單用某個佇列物件來描述"當前佇列"這一概念。 dispatch_get_current_queue
函式用於解決由不可以重入的程式碼所引發的死鎖,然後能用此函式解決的問題,通常也可以用"佇列特定資料"來解決。
最後,特別緻謝:《Effective Objective-C 2.0》第六章。
關注我們的途徑有:
QiShare(簡書)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公眾號)
推薦文章:
奇舞週刊
iOS 繪製漸變·基礎篇
iOS 繪製漸變·例項篇