以下內容主要是學習《Effective Objective-C 2.0》所做的筆記,我所購買的原書為英文原版,由於自己英文水平有限,理解可能有疏漏
原書購買地址:亞馬遜
6、Blocks and Grand Central Dispatch
Item 37: Understand Blocks
一些知識點:
(1)block結構
return_type (^block_name)(parameters)
(2)若block中引用了self,self又retain了block,則會造成循環參考。解決方案如下(用__unsafe_unretained的someObject代替self):
__unsafe_unretained SomeClass *someObject = self;
要記住的:
(1)Block在C、C++、Objective-C中是詞法閉包的。
(2)Block的參數和傳回值都是可選的。
(3)Block可以申請在堆記憶體空間、棧記憶體空間或者全域的。一個申請於棧上的block可以被拷貝到堆空間上,一但拷貝到堆空間上,那麼這個block的記憶體管理就和Objective-C的一個普通對象管理方式一樣。
Item 38: Create typedefs for Common Block Types
一些知識點:
(1)塊typedef
typedef int (^someBlock)(BOOL flag, int value)someBlock block = ^(BOOL flag, int value){};
要記住的:
(1)通過使用typedef 來使block變數更加易用。
(2)通過命名規則定義新的typedef,避免和其他的typedef造成衝突。
(3)不用擔心給同一種塊簽名定義過多的typedef。通過一個塊簽名來修改一個確定的快類型而非其他。
Item 39: Use Handler Blocks to Reduce Code Separation
要記住的:
(1)當建立對象需要將商務邏輯內聯聲明時使用處理常式塊更加有效。
(2)處理常式塊比代理方式更好的地方在於直接關聯對象,使用代理往往被多個對象所監聽。
(3)當使用代理程式塊來設計介面時,可以考慮增加一個隊列參數。隊列參數是因為塊需要被排隊處理。
Item 40: Avoid Retain Cycles Introduced by Blocks Referencing the Object Owning Them
要記住的:
(1)需要特別注意由於block擷取對象而直接和非直接的保留了對象造成的潛在循環參考問題。
(2)確保在最適當的時候打破循環參考,但不要將打破迴圈的責任交給你API的調用者。
Item 41: Prefer Dispatch Queues to Locks for Synchronization
一些知識點:
(1)同步隊列配合屏障塊
// Making the concurrent approach work with barriers_syncQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);// …- (NSString*)someString { __block NSString *localSomeString; dispatch_sync(_syncQueue, ^{ localSomeString = _someString; }); return localSomeString;}- (void)setSomeString:(NSString*)someString { dispatch_barrier_async(_syncQueue, ^{ _someString = someString; });}
要記住的:
(1)調度隊列可以用於同步語義,為@synchronized塊和NSLock對象提供一個更好的替代選擇。
(2)綜合使用同步和非同步調度可以提供一個和正常同步一樣的行為,但卻不需要因為同步操作而阻塞非同步調度。
(3)同步隊列和屏障塊可以使同步操作行為更加高效。
Item 42: Prefer GCD to performSelector and Friends
一些知識點:
(1)使用dispatch_after
[self performSelector:@selector(doSomething) withObject:nil afterDelay:5.0]; double delayInSeconds = 5.0; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ [self doSomething]; });
(2)使用dispatch_async
[self performSelectorOnMainThread:@selector(doSomething) withObject:nil waitUntilDone:NO]; dispatch_async(dispatch_get_main_queue(), ^{ [self doSomething]; });
(3)使用dispatch_sync
[self performSelectorOnMainThread:@selector(doSomething) withObject:nil waitUntilDone:YES]; dispatch_sync(dispatch_get_main_queue(), ^{ [self doSomething]; });
要記住的:
(1)performSelector系列的方法如果考慮記憶體管理的話有很大的潛在危險。如果沒有辦法確定哪個方法會被選擇,ARC無法確定在哪個地方插入合適的記憶體管理方法。
(2)performSelector系列的方法也限制了返回的資料類型和傳入方法參數的個數。
(3)對於那些可以選擇不同線程執行函數的performSelector函數,最好使用GCD的對應方法來替換。
Item 43: Know When to Use GCD and When to Use Operation Queues
要記住的:
(1)調度隊列並不是多線程和任務管理唯一的解決方案。
(2)相比較GCD來說,操作隊列提供的更加進階的Objective-C介面。並且操作隊列可以提供更加複雜的操作,相比而言GCD則需要添加一些功能代碼才能實現這些複雜操作。
Item 44: Use Dispatch Groups to Take Advantage of Platform Scaling
一些知識點:
//將隊列任務添加入非同步執行組dispatch_group_async//等待一組非同步執行的任務被執行完畢dispatch_group_wait//一組非同步任務被執行完畢時dispatch_group_notify//迭代執行dispatch_apply
要記住的:
(1)調度組主要用於管理一組任務。你可以選擇一組任務執行結束後發出通知。
(2)通過並發隊列可以使調度組同時執行多個並發任務。在這種情況下,GCD基於系統資源同時處理多個任務的調度。如果自己寫的話需要大量代碼。
Item 45: Use dispatch_once for Thread-Safe Single-Time Code Execution
一些知識點:
// `dispatch_once' singleton initialisation+ (id)sharedInstance { static EOCClass *sharedInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [[self alloc] init]; }); return sharedInstance;}
要記住的:
(1)安全執行緒的單例執行代碼是很常見的。GCD使用dispatch_once使這一過程變得更加簡單易用。
(2)記號參數(onceToken)需要被申明為static或global範圍,這樣同樣的記號參數可以被傳輸到每一個需要僅執行一次的執行塊中。
Item 46: Avoid dispatch_get_current_queue
一些知識點:
// Queue specific data exampledispatch_queue_t queueA = dispatch_queue_create("com.effectiveobjectivec.queueA", NULL);dispatch_queue_t queueB = dispatch_queue_create("com.effectiveobjectivec.queueB", NULL);dispatch_set_target_queue(queueB, queueA);static int kQueueSpecific;CFStringRef queueSpecificValue = CFSTR("queueA");dispatch_queue_set_specific(queueA, &kQueueSpecific, (void*)queueSpecificValue, (dispatch_function_t)CFRelease);dispatch_sync(queueB, ^{ dispatch_block_t block = ^{ NSLog(@"No deadlock!"); }; CFStringRef retrievedValue = dispatch_get_specific(&kQueueSpecific); if (retrievedValue) { block(); } else { dispatch_sync(queueA, block); }});
要記住的:
(1)dispatch_get_current_queue 函數並不像你像期望的那樣有用。這個方法已經被棄用,現在僅在調試時考慮使用該方法。
(2)調度隊列是一種繼承組織圖;因此,當前的隊列並不能用一個單獨的隊列對象來簡單描述。
(3)隊列具體資料可以被用於解決使用dispatch_get_current_queue造成的一般性問題,主要是阻止非重入代碼的死結。