級別: ★★☆☆☆
標籤:「iOS」「GCD」「Objective-C」
做者: MrLiuQ
審校: QiShare團隊php
前言:
這幾篇文章是小編在鑽研《Effective Objective-C 2.0》的知識產出,其中包含做者和小編的觀點,以及小編整理的一些demo。但願能幫助你們以簡潔的文字快速領悟原做者的精華。
在這裏,QiShare團隊向原做者Matt Galloway表達誠摯的敬意。git
文章目錄以下:
iOS 編寫高質量Objective-C代碼(一)
iOS 編寫高質量Objective-C代碼(二)
iOS 編寫高質量Objective-C代碼(三)
iOS 編寫高質量Objective-C代碼(四)
iOS 編寫高質量Objective-C代碼(五)
iOS 編寫高質量Objective-C代碼(六)
iOS 編寫高質量Objective-C代碼(七)
iOS 編寫高質量Objective-C代碼(八)github
本篇的主題是iOS中的 「 大中樞開發 GCD 」。面試
先簡單介紹一下今天的主角:GCD
。安全
Grand Central Dispatch
):一種與塊相關的技術,提供了對線程的抽象管理(基於派發隊列dispatch queue
)。GCD會根據系統資源狀況,適時且高效地 「建立線程」 、「複用線程」 、 「銷燬線程」。問:在iOS開發中,如何經過鎖來提供同步機制?(之前面試中,常常問道的問題..)bash
答:在GCD出現以前,有兩種方式:微信
@synchronized(self) {...}
- (void)synchronizedMethod {
@synchronized (self) {
// Safe area...
}
}
複製代碼
[_lock lock];
& [_lock unlock];
_lock = [[NSLock alloc] init];
- (void)synchronizedMethod {
[_lock lock];
// Safe area..
[_lock unlock];
}
複製代碼
不過這兩種寫法效率很低,若是有不少屬性,那麼每一個屬性的同步塊都要等其餘同步塊執行完畢才能執行。併發
GCD出現後,GCD與Block相結合,使開發變得更加簡單、高效。async
問:如何保證屬性讀寫時線程絕對安全? 答:在屬性寫入時,使用柵欄塊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;
});
}
複製代碼
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
並不必定是最佳選擇。在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
是GCD
的一項特性,可以把任務進行分組管理,而後等待這組任務執行完畢時會有通知,開發者能夠拿到結果真後繼續下一步操做。 另外,經過dispatch group
在併發隊列上同時執行多項任務的時候,GCD會根據系統資源狀態來幫忙調度這些併發執行的任務。
例如:咱們開發中寫一個單例,就可使用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
函數的行爲經常與開發者所預期的不一樣,此函數已經廢棄,只應作調試之用。GCD
是按層級來組織的,因此沒法單用某個隊列對象來描述"當前隊列"這一律念。dispatch_get_current_queue
函數用於解決由不能夠重入的代碼所引起的死鎖,而後能用此函數解決的問題,一般也能夠用"隊列特定數據"來解決。最後,特別緻謝:《Effective Objective-C 2.0》第六章。
關注咱們的途徑有:
QiShare(簡書)
QiShare(掘金)
QiShare(知乎)
QiShare(GitHub)
QiShare(CocoaChina)
QiShare(StackOverflow)
QiShare(微信公衆號)
推薦文章:
奇舞週刊
iOS 繪製漸變·基礎篇
iOS 繪製漸變·實例篇