




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、GCD 多線程API編程筆記GCD 是 iOS 編程中實(shí)現(xiàn)多線程的常用 API,使用方便,無(wú)須進(jìn)行線程的管理,由系統(tǒng)代勞。同時(shí)GCD基于C實(shí)現(xiàn),性能強(qiáng)。 在名著Pro multithreading and memory management for iOS and OS X(中文名:Objective-C 高級(jí)編程 iOS與 OSX多線程和內(nèi)存管理)中,專門有章節(jié)講解,特根據(jù)此書(shū)講解做些筆記。一 概要GCD是Grand Central Dispatch(GCD)的縮寫(xiě),是異步執(zhí)行任務(wù)的技術(shù)之一。一般將應(yīng)用程序中記述的線程管理用的代碼在系統(tǒng)級(jí)中實(shí)現(xiàn)。開(kāi)發(fā)者只需定義想執(zhí)行的任務(wù),然后加入適當(dāng)?shù)?D
2、ispatch Queue 中,GCD 就能生成相應(yīng)的線程并計(jì)劃執(zhí)行任務(wù)。 由于線程管理是系統(tǒng)來(lái)實(shí)現(xiàn)的,因此可以統(tǒng)一管理,也可執(zhí)行任務(wù),這樣就比之前的線程更有效率。二 API 詳解1. Dispatch Queue“Dispatch Queue” 是執(zhí)行處理的等待隊(duì)列。應(yīng)用程序編程通過(guò) dispatch_async函數(shù)等 API,在 Block 語(yǔ)法中記述想執(zhí)行的處理,并將其追加到 Dispatch Queue 中。 Dispatch Queue 按照追加的順序 (先進(jìn)先出FIFO,F(xiàn)irst In Firs Out)執(zhí)行處理。 根據(jù)處理的策略,分為兩種Dispatch Queue, 一種是等
3、待現(xiàn)在執(zhí)行中處理的Serial Dispatch Queue;另外一種是不等待現(xiàn)在執(zhí)行任務(wù)隊(duì)列處理的 Concurrent Dispatch Queue。 比較Dispatch Queue的種類如下:Dispatch Queue的種類種類名稱 執(zhí)行情況 Serial Dispatch Queue等待現(xiàn)在執(zhí)行中處理結(jié)束 Concurrent Dispatch Queue.不等待現(xiàn)在執(zhí)行處理結(jié)束準(zhǔn)備以下源代碼,在dispatch_async中追加多個(gè)處理。/ Demo code 1dispatch_async(queue, blk0);dispatch_async(queue, blk1);dis
4、patch_async(queue, blk2);dispatch_async(queue, blk3);dispatch_async(queue, blk4);dispatch_async(queue, blk5);dispatch_async(queue, blk6);dispatch_async(queue, blk7);當(dāng)變量queue為Serial Dispatch Queue 時(shí),因?yàn)橐却F(xiàn)在執(zhí)行中的處理結(jié)束,所以首先執(zhí)行任務(wù) blk0 ,待 blk0 執(zhí)行結(jié)束后,接著執(zhí)行 blk1, blk1 結(jié)束后再開(kāi)始執(zhí)行 blk2,如此重復(fù)。同時(shí)執(zhí)行的任務(wù)只能為1個(gè)。即執(zhí)行源代碼片段De
5、mo code 1后,按照以下順序進(jìn)行處理。blk0blk1blk2blk3blk4blk5blk6blk7但當(dāng)變量 queue 為 Concurrent Dispatch Queue 時(shí),因?yàn)椴挥玫却F(xiàn)在執(zhí)行中的處理結(jié)束,所以執(zhí)行順序?qū)⒆兂桑?首先執(zhí)行 blk0, 不管 blk0 的執(zhí)行是否結(jié)束,都開(kāi)始執(zhí)行后面的 blk1, 不管 blk1 的執(zhí)行是否結(jié)束,都開(kāi)始執(zhí)行后面的 blk2, 如此重復(fù)循環(huán)。 這樣雖然不用等待處理結(jié)束,可以并行執(zhí)行多個(gè)處理,但并行執(zhí)行的處理數(shù)量取決于當(dāng)前系統(tǒng)的狀態(tài)。 即 iOS 和 OS X 基于 Dispatch Queue 中的處理數(shù)、CPU 核數(shù)及 CPU 負(fù)
6、荷等當(dāng)前系統(tǒng)的狀態(tài)來(lái)決定 Concurrent Dispatch Queue 中并行執(zhí)行的處理數(shù)。 所謂“并行執(zhí)行”,就是使用多個(gè)線程同時(shí)執(zhí)行多個(gè)處理。 總結(jié)來(lái)說(shuō),Serial Dispatch Queue 使用一個(gè)線程;而Concurrent Dispatch Queue 使用的是多個(gè)線程。 iOS 和 OS X的核心 XNU 內(nèi)核決定應(yīng)當(dāng)使用的線程數(shù),并只生成所需的線程執(zhí)行處理。另外,當(dāng)處理結(jié)束,應(yīng)當(dāng)執(zhí)行的處理數(shù)減少時(shí),XNU內(nèi)核會(huì)結(jié)束不再需要的線程。 XNU 內(nèi)核僅使用 Concurrent Dispatch Queue 便可完美地管理并行執(zhí)行多個(gè)處理的線程。假設(shè)準(zhǔn)備4個(gè) Concurr
7、ent Dispatch Queue 使用的線程。首先:blk0 在線程0中開(kāi)始執(zhí)行,接著blk1在線程1中、blk2在線程2中、blk3在線程3中開(kāi)始執(zhí)行。線程0中blk0執(zhí)行結(jié)束后,開(kāi)始執(zhí)行blk4,由于線程1中blk1的執(zhí)行沒(méi)有結(jié)束,因此線程數(shù)中blk2執(zhí)行結(jié)束后開(kāi)始執(zhí)行blk5,就這樣循環(huán)往復(fù)。Concurrent Dispatch Queue 執(zhí)行示例 thread0 _ thread1 _ hread2 _ hread3 blk0 = blk1 = blk2 = blk3 blk4 = blk5 blk7像這樣在Concurrent Dispatch Queue中執(zhí)行處理時(shí),執(zhí)行順
8、序會(huì)根據(jù)處理內(nèi)容和系統(tǒng)狀態(tài)發(fā)生改變。 它不同于執(zhí)行順序固定的 Serial Dispatch Queue。在不能改變執(zhí)行的處理順序或不想并行執(zhí)行多個(gè)處理時(shí)使用 Serial Dispatch Queue。 那么如何得到這兩種Queue呢?方法有兩種。2. dispatch_queue_create第一種方式是使用GCD的API生成 Dispatch Queue. 通過(guò) dispatch_queue_create 函數(shù)可生成 Dispatch Queue。 以下源代碼生成了 Serial Dispatch Queue。dispatch_queuet mySerialDispatchQueue =
9、 dispatch_queue_create("com.example.gcd.MySerialDispatchQueue", NULL);根據(jù)蘋果的API函數(shù)聲明:/*! * function dispatch_queue_create * * abstract * Creates a new dispatch queue to which blocks may be submitted. * * discussion * Dispatch queues created with the DISPATCH_QUEUE_SERIAL or a NULL attribute
10、* invoke blocks serially in FIFO order. * * Dispatch queues created with the DISPATCH_QUEUE_CONCURRENT attribute may * invoke blocks concurrently (similarly to the global concurrent queues, but * potentially with more overhead), and support barrier blocks submitted with * the dispatch barrier API, w
11、hich e.g. enables the implementation of efficient * reader-writer schemes. * * When a dispatch queue is no longer needed, it should be released with * dispatch_release(). Note that any pending blocks submitted to a queue will * hold a reference to that queue. Therefore a queue will not be deallocate
12、d * until all pending blocks have finished. * * Passing the result of the dispatch_queue_attr_make_with_qos_class() function * to the attr parameter of this function allows a quality of service class and * relative priority to be specified for the newly created queue. * The quality of service class
13、so specified takes precedence over the quality * of service class of the newly created dispatch queue's target queue (if any) * as long that does not result in a lower QOS class and relative priority. * * When no quality of service class is specified, the target queue of a newly * created dispat
14、ch queue is the default priority global concurrent queue. * * param label * A string label to attach to the queue. * This parameter is optional and may be NULL. * * param attr * DISPATCH_QUEUE_SERIAL, DISPATCH_QUEUE_CONCURRENT, or the result of a call to * the function dispatch_queue_attr_make_with_
15、qos_class(). * * result * The newly created dispatch queue. */_OSX_AVAILABLE_STARTING(_MAC_10_6,_IPHONE_4_0)DISPATCH_EXPORT DISPATCH_MALLOC DISPATCH_RETURNS_RETAINED DISPATCH_WARN_RESULTDISPATCH_NOTHROWdispatch_queue_tdispatch_queue_create(const char *label, dispatch_queue_attr_t attr);dispatch_queu
16、e_create 函數(shù)的第一個(gè)參數(shù)是表示隊(duì)列名;第二個(gè)參數(shù)表示隊(duì)列的種類,聲明為NULL表示串行隊(duì)列,與參數(shù)DISPATCH_QUEUE_SERIAL 同樣的效果表示串行隊(duì)列。 關(guān)于 Serial Dispatch Queue生成個(gè)數(shù)的注意事項(xiàng)如下:Serial Dispatch Queue 同時(shí)只能執(zhí)行1個(gè)追加處理。雖然 Serial Dispatch Queue 和 Concurrent Dispatch Queue 受到系統(tǒng)資源的限制,但用 dispatch_queue_create 函數(shù)可生成任意多個(gè) Dispatch Queue。 當(dāng)生成多個(gè) Serial Dispatch Queu
17、e 時(shí),在每個(gè) Serial Dispatch Queue 中,同時(shí)只能執(zhí)行一個(gè)追加處理,但各個(gè) Serial Dispatch Queue 將并行執(zhí)行,達(dá)到同時(shí)執(zhí)行多個(gè)任務(wù)處理的效果。一旦生成 Serial Dispatch Queue 并追加處理,系統(tǒng)對(duì)于一個(gè) Serial Dispatch Queue 就只生成并使用一個(gè)線程。 如果生成2000個(gè) Serial Dispatch Queue, 那么就生成2000 個(gè)線程。 但是如果使用多線程,就會(huì)消耗大量?jī)?nèi)存,引起大量的上下文切換,大幅度降低系統(tǒng)的響應(yīng)性能。 只在避免多線程編程問(wèn)題之一 多個(gè)線程更新相同資源導(dǎo)致數(shù)據(jù)競(jìng)爭(zhēng)時(shí)使用 Serial
18、 Dispatch Queue。 但 Serial Dispatch Queue 的生成個(gè)數(shù)應(yīng)當(dāng)僅限所必需的數(shù)量。 例如更新數(shù)據(jù)庫(kù)時(shí)1 個(gè)表生成1 個(gè) Serial Dispatch Queue,更新文件時(shí)1個(gè)文件或是可以分割的1個(gè)文件塊生成1個(gè) Serial Dispatch Queue. 雖然“Serial Dispatch Queue 比 Concurrent Dispatch Queue 能生成更多的線程”,但絕不能激動(dòng)之下大量生成 Serial Dispatch Queue。 當(dāng)想并行執(zhí)行不發(fā)生數(shù)據(jù)競(jìng)爭(zhēng)等問(wèn)題的處理時(shí),使用 Concurrent Dispatch Queue。而且對(duì)于
19、Concurrent Dispatch Queue 來(lái)說(shuō),不管生成多少,由于XNU內(nèi)核只使用有效管理的線程,因此不會(huì)發(fā)生 Serial Dispatch Queue 的那些問(wèn)題。 繼續(xù)講 dispatch_queue_create 函數(shù)。該函數(shù)的第一個(gè)參數(shù)指定 Serial Dispatch Queue 的名稱。像此源代碼這樣, Dispatch Queue 的名稱推薦使用應(yīng)用程序 ID 這種逆序全程域名(FQDN,fully qualified domain name)。該名稱在 XCode 和Instruments 的調(diào)試器中作為 Dispatch Queue 名稱來(lái)表示。另外,該名稱也會(huì)
20、出現(xiàn)在應(yīng)用程序崩潰時(shí)所生成的 crashLog 中。 我們命名時(shí)應(yīng)遵循這樣的原則:對(duì)編程人員和用戶來(lái)說(shuō)都要易懂。如果嫌命名麻煩設(shè)為 NULL 也可以,但在調(diào)試中一定會(huì)后悔沒(méi)有為 Dispatch Queue 署名。 生成 Serial Dispatch Queue 時(shí),像該源代碼這樣,將第二個(gè)參數(shù)指定為NULL。生成Concurrent Dispatch Queue時(shí),像下面源代碼一樣,指定為 DISPATCH_QUEUE_CONCURRENT。dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create("co
21、m.example.gcd.MyConcurrentDispatchQueue", DISPATCH_QUEUE_CONCURRENT);dispatch_async(myConcurrentDispatchQueue,NSLog("block on myConcurrentDispatchQueue"););并在生成的 Concurrent Dispatch Queue 中執(zhí)行指定的Block。 另外,遺憾的是盡管有ARC這一通過(guò)編譯器自動(dòng)管理內(nèi)存的優(yōu)秀技術(shù),但生成的Dispatch Queue必須由程序員負(fù)責(zé)釋放。這是因?yàn)镈ispatch Queue并沒(méi)有像B
22、lock那樣具有作為Objective-C對(duì)象來(lái)處理的技術(shù)。 通過(guò) dispatch_queue_create 函數(shù)生成的 Dispatch Queue 在使用結(jié)束后通過(guò) dispatch_release 函數(shù)釋放。dispatch_release(mySerialDispatchQueue);相應(yīng)地,也存在dispatch_retain函數(shù)。dispatch_retain(myConcurrentDispatchQueue);即Dispatch Queue也像 Objective-C的飲用技術(shù)式內(nèi)存管理一樣,需要通過(guò) dispatch_retain 函數(shù)和 dispatch_release
23、函數(shù)的引用計(jì)數(shù)來(lái)管理內(nèi)存。在前面的源代碼中,需要釋放通過(guò) dispatch_queue_create 函數(shù)生成并賦值給變量 myConcurrentDispatchQueue 中的 Concurrent Dispatch Queue。 再看一個(gè)例子:dispatch_queue_t myConcurrentDispatchQueue = dispatch_queue_create("com.demo.gcd.myConcurrentDispatchQueue",DISPATCH_QUEUE_CONCURRENT);dispatch_async(myConcurrentDis
24、patchQueue,NSLog("block on myConcurrentDispatchQueue"););dispatch_release(myConcurrentDispatchQueue);雖然 Concurrent Dispatch Queue 是使用多線程進(jìn)行的追加處理,但像該例這樣,在 dispatch_async 函數(shù)中追加 Block 到Concurrent Dispatch Queue,并立即通過(guò) dispatch_release函數(shù)進(jìn)行釋放是否可以呢? 該源代碼完全沒(méi)有問(wèn)題。在 dispatch_async 函數(shù)中追加 Block 到 Dispat
25、ch Queue ,換言之:該 Block 通過(guò) dispatch_retain 函數(shù)持有 Dispatch Queue。無(wú)論 Dispatch Queue 是 Serial Dispatch Queue 還是 Concurrent Dispatch Queue 都一樣。一旦Block 執(zhí)行結(jié)束,就通過(guò) dispatch_release 函數(shù)釋放該 Block 持有的 Dispatch Queue。 也就是說(shuō),在 dispatch_async 函數(shù)中追加 Block 到 Dispatch Queue 后,即使立即釋放 Dispatch Queue,該 Dispatch Queue 由于被 Bl
26、ock 所持有也不會(huì)被廢棄,因而 Block 能夠執(zhí)行。 Block 執(zhí)行結(jié)束后會(huì)釋放 Dispatch Queue,這時(shí)誰(shuí)都不持有 Dispatch Queue,因此它會(huì)被釋放。 另外,能夠使用 dispatch_retain 函數(shù)和 dispatch_release 函數(shù)的地方不僅是在 Dispatch Queue 中。在之后介紹的幾個(gè) GCD 的 API中,名稱中含有“create”的 API 在不需要其生成的對(duì)象時(shí),有必要通過(guò) dispatch_release 函數(shù)進(jìn)行釋放。在通過(guò)函數(shù)或方法獲取 Dispatch Queue 以及其它名稱中含有 create 的 API 生成的對(duì)象時(shí),
27、有必要通過(guò) dispatch_retain 函數(shù)持有,并在不需要時(shí)通過(guò) dispatch_release 函數(shù)釋放。3. Main Dispatch Queue / Global Dispatch Queue第二種方法是獲取系統(tǒng)標(biāo)準(zhǔn)提供的Dispatch Queue。 實(shí)際上不用特意生成 Dispatch Queue 系統(tǒng)也會(huì)給我們提供幾個(gè)。那就是 Main Dispatch Queue 和 Global Dispatch Queue。 3.1 Main Dispatch Queue 主線程中執(zhí)行的 Dispatch Queue,因?yàn)橹骶€程只有一個(gè),所以 Main Dispatch Queue
28、 自然就是 Serial Dispatch Queue。 追加到 Main Dispatch Queue 中的任務(wù)在主線程的 RunLoop 中執(zhí)行。由于在主線程中執(zhí)行,因此將用戶界面更新等一些必須在主線程中執(zhí)行的處理追加到 Main Dispatch Queue 中使用。這正好和 NSObject 類的 performSelectorOnMainThread 實(shí)例方法相同。 3.2 Global Dispatch Queue 所有程序都可以使用,沒(méi)有必要通過(guò) dispatch_、queue_create 函數(shù)逐個(gè)生成 Concurrent Dispatch Queue 。只要獲取 Globa
29、l Dispatch Queue 即可。 Global Dispatch Queue 具有4個(gè)優(yōu)先級(jí),分別是: 1)高優(yōu)先級(jí) (High Priority) 2) 默認(rèn)優(yōu)先級(jí)(Default Priority) 3) 低優(yōu)先級(jí)(Low Priority) 4) 后臺(tái)優(yōu)先級(jí) (Background Priority). 通過(guò) XNU 內(nèi)核管理的用于 Global Dispatch Queue 的線程,將各自使用的 Global Dispatch Queue 的執(zhí)行優(yōu)先級(jí)作為線程的優(yōu)先級(jí)來(lái)使用。在向 Global Dispatch Queue 追加處理時(shí),應(yīng)選擇與處理內(nèi)容執(zhí)行優(yōu)先級(jí)一致的 Glob
30、al Dispatch Queue。 但是通過(guò)XNU內(nèi)核用于 Global Dispatch Queue 的線程并不能保證實(shí)時(shí)性,因此執(zhí)行優(yōu)先級(jí)只是大致的判斷。例如在處理內(nèi)容的執(zhí)行可有可無(wú)時(shí),使用后臺(tái)優(yōu)先級(jí)的 Global Dispatch Queue 等,只能進(jìn)行這種程度的劃分。系統(tǒng)提供的 Dispatch Queue 總結(jié)如下表: Dispatch Queue 的種類 名稱種類說(shuō)明 Main Dispatch QueueSerial Dispatch Queue主線程執(zhí)行 Global Dispatch Queue(High Priority)Concurrent Dispatch Que
31、ue-執(zhí)行優(yōu)先級(jí):高 Global Dispatch Queue(Default Priority)Concurrent Dispatch Queue-執(zhí)行優(yōu)先級(jí):默認(rèn) Global Dispatch Queue(Low Priority)Concurrent Dispatch Queue-執(zhí)行優(yōu)先級(jí):低 Global Dispatch Queue(Background Priority)Concurrent Dispatch Queue-執(zhí)行優(yōu)先級(jí):后臺(tái) 各種 Dispatch Queue 的獲取方法如下:/Main Dispatch Queue的獲取方法dispatch_queue_t m
32、ainDispatchQueue = dispatch_get_main_queue();/Global Dispatch Queue(高優(yōu)先級(jí))的獲取方法dispatch_queue_t globalDispatchQueueHigh = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY,0);/Global Dispatch Queue(默認(rèn)優(yōu)先級(jí))的獲取方法dispatch_queue_t globalDispatchQueueDefault = dispatch_get_global_queue(DISPATCH_QUEUE_PRIOR
33、ITY_DEFAULT,0);/Global Dispatch Queue(低優(yōu)先級(jí))的獲取方法dispatch_queue_t globalDispatchQueueLow = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0);/Global Dispatch Queue(后臺(tái)優(yōu)先級(jí))的獲取方法dispatch_queue_t globalDispatchQueueBackground = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0);對(duì)于Main
34、 Dispatch Queue和 Global Dispatch Queue執(zhí)行 dispatch_retain 和 dispatch_release 函數(shù)不會(huì)引起任何變化,也不會(huì)有任何問(wèn)題。這也是獲取并使用 Global Dispatch Queue 比生成、使用、釋放 Concurrent Dispatch Queue輕松的原因。 當(dāng)然,源代碼上進(jìn)行類似通過(guò) dispatch_queue_create 函數(shù)生成 Dispatch Queue 的處理要更輕松時(shí),可參照引用計(jì)數(shù)內(nèi)存管理的思維方式,直接在 Main Dispatch Queue 和 Global Dispatch Queue中執(zhí)
35、行 dispatch_retain 和 dispatch_release 函數(shù)。 使用 Main Dispatch Queue 和 Global Dispatch Queue 的源代碼如下:/在默認(rèn)優(yōu)先級(jí)的Global Dispatch Queue中執(zhí)行 Blockdispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), /可并行執(zhí)行的處理 /在 Main Dispatch Queue 中執(zhí)行 Block dispatch_async(dispatch_get_main_queue(), /只能在主
36、線程中進(jìn)行的處理 /比如:UI操作 ););4. dispatch_set_target_queuedispatch_queue_create 函數(shù)生成的 Dispatch Queue 不管是 Serial Dispatch Queue 還是 Concurrent Dispatch Queue, 都使用與默認(rèn)優(yōu)先級(jí) Global Dispatch Queue 相同執(zhí)行優(yōu)先級(jí)的線程。而變更生成的 Dispatch Queue 的執(zhí)行優(yōu)先級(jí)要使用 dispatch_set_target_queue 函數(shù)。在后臺(tái)執(zhí)行動(dòng)作處理的 Serial Dispatch Queue 的生成方法如下:dispat
37、ch_queue_t mySerialDispatachQueue = dispatch_queue_create("com.example.gcd.MySerialDispatchQueue",NULL);dispatch_queue_t globalDispatachQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0);dispatch_set_target_queue(mySerialDispatchQueue,globalDispatchQueueBackground);指定要
38、變更執(zhí)行優(yōu)先級(jí)的 Dispatch Queue 為 dispatch_set_target_queue 函數(shù)的第一個(gè)參數(shù),第二個(gè)參數(shù)指定為與要使用的執(zhí)行優(yōu)先級(jí)相同優(yōu)先級(jí)的 Global Dispatch Queue。前者為待變更的 Dispatch Queue, 后者為指定優(yōu)先級(jí)的目標(biāo) Dispatch Queue。 第一個(gè)參數(shù)如果指定系統(tǒng)提供的 Main Dispatch Queue 和 Global Dispatch Queue 則不知道會(huì)出現(xiàn)什么狀況,因此這些均不可指定。將 Dispatch Queue 指定為 dispatch_set_target_queue 函數(shù)的參數(shù),不僅可以變更
39、 Dispatch Queue的執(zhí)行優(yōu)先級(jí),還可以作為 Dispatch Queue 的執(zhí)行階層。如果在多個(gè) Serial Dispatch Queue 中用 dispatch_set_target_queue 函數(shù)指定目標(biāo)為某一個(gè) Serial Dispatch Queue,那么原先本應(yīng)并行執(zhí)行的多個(gè) Serial Dispatch Queue,在目標(biāo) Serial Dispatch Queue 上只能同時(shí)執(zhí)行一個(gè)處理。 在必須將不可并行執(zhí)行的處理追加到多個(gè) Serial Dispatch Queue 中時(shí),如果使用 dispatch_set_target_queue 函數(shù)將目標(biāo)指定為某一個(gè)
40、 Serial Dispatch Queue,即可防止處理并行執(zhí)行。5. dispatch_after想在指定時(shí)間后執(zhí)行處理,可使用 dispatch_after 函數(shù)來(lái)實(shí)現(xiàn)。 在3秒后將指定的 Block 追加到 Main Dispatch Queue 中的源代碼如下:dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 3ull *NSEC_PER_SEC);dispatch_after(time,dispatch_get_main_queue(), NSLog("waited at least 3 seconds.&qu
41、ot;););需要注意()的是:dispatch_after 函數(shù)并不是在指定時(shí)間后執(zhí)行處理,而只是在指定時(shí)間后追加處理到 Dispatch Queue。上述源代碼與在3秒后用 dispatch_async函數(shù)追加 Block 到 Main Dispatch Queue 的相同。 因?yàn)?Main Dispatch Queue 在主線程的 RunLoop 中執(zhí)行, 所以在比如每隔 1/60 秒執(zhí)行的 RunLoop 中,Block 最快在 3 秒后執(zhí)行,最慢在 (3+1/60)秒后執(zhí)行,并且在 Main Dispatch Queue 中有大量處理任務(wù)或主線程的處理本身有延遲時(shí),這個(gè)時(shí)間會(huì)更長(zhǎng)。雖
42、然在嚴(yán)格的時(shí)間要求下使用會(huì)出現(xiàn)問(wèn)題,但在大致想延遲執(zhí)行處理時(shí),該函數(shù)非常有效。 另外,第二個(gè)參數(shù)指定要追加處理的 Dispatch Queue, 第三個(gè)參數(shù)指定記述要處理的Block。 第一個(gè)參數(shù)是指定時(shí)間用的 dispatch_time_t 類型的值。該值可以使用dispatch_time 或 dispatch_walltime 函數(shù)生成。 1)dispatch_time 生成函數(shù) 計(jì)算相對(duì)時(shí)間dispatch_time_tdispatch_time(dispatch_time_t when, int64_t delta);中第一個(gè)參數(shù)when起始的時(shí)間開(kāi)始,到第二個(gè)參數(shù)delta指定的毫微
43、秒單位時(shí)間后的時(shí)間。when經(jīng)常使用的值是之前源代碼中出現(xiàn)的DISPATCH_TIME_NOW這表示現(xiàn)在的時(shí)間,即以下源代碼可得到表示從現(xiàn)在開(kāi)始1秒后的dispatch_time_t 類型的值。dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW,1ull * NSEC_PER_SEC);數(shù)值和 NSEC_PER_SEC的乘積得到單位為毫微秒的數(shù)值?!皍ll”是C語(yǔ)言的數(shù)值字面量,是顯示表明類型時(shí)使用的字符串(表示“unsigned long long”)。如果使用 NSEC_PER_MSEC則可以以毫秒為單位計(jì)算。以下代碼獲取表示從現(xiàn)在
44、開(kāi)始150毫秒后時(shí)間的值。dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW,150ull * NSEC_PER_MSEC);2) dispatch_walltime 函數(shù)由POSIX中使用的 struct timespec 類型的時(shí)間得到 dispatch_time_t 類型的值。 用于計(jì)算絕對(duì)時(shí)間。例如在 dispatch_after 函數(shù)中想指定 2011 年 11 月 11 日 11 時(shí) 11 分 11秒 這一絕對(duì)時(shí)間的情況,這可作為粗略的鬧鐘功能使用。 struct timespec 類型的時(shí)間可以很輕松地通過(guò) NSDate
45、類對(duì)象生成。下面是示例代碼:dispatch_time_t getDispatchTimeByDate(NSDate *date) NSTimeInterval interval; double second, subsecond; struct timespec time; dispatch_time_t milestone; interval = date timeIntervalSince1970; subsecond = modf(interval, &second); time.tv_sec = cond; time.tv_nsec = subsecond * NSEC_PE
46、R_SEC; milestone = dispatch_walltime(&time, 0); retuen milestone;其中modf函數(shù)是獲取double數(shù)值的分?jǐn)?shù)(小數(shù))部分的值,同時(shí)將整數(shù)部分存儲(chǔ)到第二個(gè)參數(shù) second中,參考這個(gè)英文網(wǎng)站和這個(gè)中文網(wǎng)站的解釋:function: modf (param , &intpart) Break into fractional and integral parts Breaks x into an integral and a fractional part.The integer part is stored in
47、the object pointed by intpart, and the fractional part is returned by the function.Both parts have the same sign as x.6. Dispatch Group在追加到 Dispatch Queue 中的多個(gè)處理全部結(jié)束后想執(zhí)行結(jié)束處理,這種情況會(huì)經(jīng)常出現(xiàn)。 只使用一個(gè) Serial Dispatch Queue 時(shí),只要將想執(zhí)行的處理全部追加到該 Serial Dispatch Queue 中并在最后追加結(jié)束處理,即可實(shí)現(xiàn)。但在使用 Concurrent Dispatch Queue
48、 時(shí)或同時(shí)使用多個(gè) Dispatch Queue 時(shí),源代碼就會(huì)變得頗為復(fù)雜。 在此種情況下可以使用Dispatch Group。比如:追加3個(gè)Block到 Global Dispatch Queue, 這些 Block 如果全部執(zhí)行完畢,就會(huì)執(zhí)行 Main Dispatch Queue中結(jié)束處理用的 Block。dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); disp
49、atch_group_async(group, queue, NSLog("blk0"); ); dispatch_group_async(group, queue, NSLog("blk1"); ); dispatch_group_async(group, queue, NSLog("blk2"); ); dispatch_group_notify(group, dispatch_get_main_queue(), NSLog("done"); ); / dispatch_release(group);經(jīng)過(guò)實(shí)際測(cè)
50、試:dispatch_release(group);代碼必須注釋掉,因?yàn)樵贏RC環(huán)境下該代碼會(huì)報(bào)錯(cuò): “ARC forbids explicit message send of release”. 該源代碼的執(zhí)行結(jié)果如下:blk0blk2blk1done因?yàn)橄?Global Dispatch Queue 即 Concurrent Dispatch Queue 追加處理, 多個(gè)線程并行執(zhí)行,所以追加處理的執(zhí)行順序不定。執(zhí)行時(shí)的順序會(huì)發(fā)生變化,但是最后輸出 done。 無(wú)論向什么樣的 Dispatch Queue 中追加處理,使用 Dispatch Group 都可監(jiān)視這些處理執(zhí)行的結(jié)束。一旦檢測(cè)
51、到所有處理執(zhí)行結(jié)束,就可將結(jié)束的處理追加到 Dispatch Queue 中。這就是使用 Dispatch Group 的原因。 首先 dispatch_group_create 函數(shù)生成 dispatch_group_t 類型的Dispatch Group。如 dispatch_group_create 函數(shù)名中所含的 create所示,該 Dispatch Group 與 Dispatch Queue 相同,在使用結(jié)束后需要通過(guò) dispatch_release 函數(shù)釋放(在ARC模式下不用)。 另外,與追加Block到 Dispatch Queue 時(shí)同樣,Block通過(guò) dispatc
52、h_retain 函數(shù)持有 Dispatch Group,從而使得該 Block 屬于 Dispatch Group。這樣如果 Block 執(zhí)行結(jié)束,該 Block 就通過(guò)dispatch_release 函數(shù)釋放持有的 Dispatch Group。 一旦 Dispatch Group 使用結(jié)束,不用考慮屬于該 Dispatch Group 的 Block,立即通過(guò) dispatch_release 函數(shù)釋放即可。 在追加到 Dispatch Group 中的處理全部執(zhí)行結(jié)束時(shí),該源代碼中使用的 dispatch_group_notify 函數(shù)會(huì)將執(zhí)行的 block 追加到 queue中,將
53、第一個(gè)參數(shù)指定為要監(jiān)視的 group。在追加到該 Dispatch Group 的全部處理執(zhí)行結(jié)束時(shí),將第三個(gè)參數(shù)的 block 追加到第二個(gè)參數(shù)的 queue(Dispatch Queue)中。在 dispatch_group_notify函數(shù)中不管指定什么樣的 Dispatch Queue,屬于 Dispatch Group的全部處理在追加指定的 Block 時(shí)都已執(zhí)行結(jié)束。 函數(shù)原型為:dispatch_group_notify(dispatch_group_t group, dispatch_queue_t queue, dispatch_block_t block);另外,在 Dis
54、patch Group 中也可以使用 dispatch_group_wait 函數(shù)等待全部處理執(zhí)行結(jié)束。dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, queue, NSLog("blk0"); ); dispatch_group_async(group, queue, NSLog("
55、blk1"); ); dispatch_group_async(group, queue, NSLog("blk2"); ); dispatch_group_wait(group, DISPATCH_TIME_FOREVER);dispatch_group_wait 的函數(shù)原型為:/*! * function dispatch_group_wait * * abstract * Wait synchronously until all the blocks associated with a group have * completed or until the
56、specified timeout has elapsed. * * discussion * This function waits for the completion of the blocks associated with the * given dispatch group, and returns after all blocks have completed or when * the specified timeout has elapsed. When a timeout occurs, the group is * restored to its original state. * * This function will return immediately if there are no blocks associated * with the dispatch group (i.e. the group is empty). * * The result of calling this function from multiple threads simultaneous
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 三農(nóng)村住房建設(shè)標(biāo)準(zhǔn)手冊(cè)
- 三農(nóng)村信息化應(yīng)用推廣手冊(cè)
- 綜合物流服務(wù)方案
- 鎮(zhèn)江2025年江蘇大學(xué)附屬醫(yī)院招聘編外工作人員40人(一)筆試歷年參考題庫(kù)附帶答案詳解
- 濟(jì)南山東濟(jì)南泉商調(diào)解中心招聘高級(jí)調(diào)解員30人筆試歷年參考題庫(kù)附帶答案詳解
- 替米沙坦聯(lián)合氫氯噻嗪在高血壓患者治療中的應(yīng)用效果分析
- 高壓線路 安全事故免責(zé)協(xié)議書(shū)(2篇)
- 惠水縣旅游介紹
- 新能源項(xiàng)目述職報(bào)告
- 腹瀉的治療方法
- 名著《駱駝祥子》中考真題及典型模擬題訓(xùn)練(原卷版)
- (2025春新教材)人教版七年級(jí)英語(yǔ)下冊(cè)全冊(cè)教案
- 山東黃河河務(wù)局公開(kāi)招考2025高校畢業(yè)生易考易錯(cuò)模擬試題(共500題)試卷后附參考答案
- 2025年北京電子科技職業(yè)學(xué)院高職單招數(shù)學(xué)歷年(2016-2024)頻考點(diǎn)試題含答案解析
- 《信用工具與外匯》課件
- 煤礦隱蔽致災(zāi)因素普查
- 2024年國(guó)家公務(wù)員考試行測(cè)真題附解析答案
- 中學(xué)生保護(hù)眼睛預(yù)防近視
- 古往今來(lái)數(shù)學(xué)家的奇聞?shì)W事
- 探訪榴蓮老家-走進(jìn)東南亞 課件 高二下學(xué)期 地理
- 部隊(duì)保密安全課件
評(píng)論
0/150
提交評(píng)論