您好,歡迎來電子發(fā)燒友網(wǎng)! ,新用戶?[免費(fèi)注冊(cè)]

您的位置:電子發(fā)燒友網(wǎng)>源碼下載>通訊/手機(jī)編程>

Dispatch Queue任務(wù)執(zhí)行與Dispatch Source

大?。?/span>0.5 MB 人氣: 2017-10-11 需要積分:1
 導(dǎo)讀本文為讀《Concurrency Programming Guide》筆記第三篇,在對(duì)OS X和iOS應(yīng)用開發(fā)中實(shí)現(xiàn)任務(wù)異步執(zhí)行的技術(shù)、注意事項(xiàng)、Operation與Dispatch Queues實(shí)踐解析后,作者付宇軒(@DevTalking)著重分享了讓Dispatch Queue執(zhí)行任務(wù)的那些事兒。當(dāng)然,本著“Talk is cheap, show me the code”原則,除卻講解外,作者還分享了各個(gè)知識(shí)點(diǎn)具體操作實(shí)現(xiàn)的Swift代碼片段。
  系列閱讀(文章點(diǎn)擊【閱讀原文】)
  iOS開發(fā)中設(shè)計(jì)并發(fā)任務(wù)技術(shù)與注意事項(xiàng)
  iOS并發(fā)編程中Operation與Dispatch Queues實(shí)踐
  iOS并發(fā)編程指南:Dispatch Queue任務(wù)執(zhí)行與Dispatch Source
  通過Dispatch Queue執(zhí)行任務(wù)
  如果想讓Dispatch Queue執(zhí)行任務(wù),首先就是得將任務(wù)放入隊(duì)列中,我們可以異步的將任務(wù)加入隊(duì)列,也可以同步的將任務(wù)加入隊(duì)列,可以一個(gè)任務(wù)一個(gè)任務(wù)的加,也可以一組一組的加。這節(jié)我們就來看看將任務(wù)加入隊(duì)列的那些事。
  向隊(duì)列添加任務(wù)
  我們可以使用dispatch_async或者dispatch_async_f函數(shù)異步的向隊(duì)列中添加任務(wù),也就是說當(dāng)我們添加完任務(wù)后該函數(shù)會(huì)立即返回,我們不需要等待任務(wù)執(zhí)行完成,而且我們也不會(huì)知道隊(duì)列到底何時(shí)開始執(zhí)行任務(wù)。dispatch_async函數(shù)有兩個(gè)參數(shù),一個(gè)是目標(biāo)隊(duì)列,類型為dispatch_queue_t,另一個(gè)是閉包,類型為dispatch_block_t:
  let serialQueue = dispatch_queue_create(“com.example.MySerialQueue”, nil)
  dispatch_async(serialQueue, {
  print(“Task in the queue.。.”)
  })
  dispatch_async_f函數(shù)有三個(gè)參數(shù),第一個(gè)是類型為dispatch_queue_t的目標(biāo)隊(duì)列,第二個(gè)是隊(duì)列上下文指針,第三個(gè)是類型為dispatch_function_t的任務(wù)函數(shù),隊(duì)列上下文指針為該函數(shù)的唯一參數(shù):
  class AddTaskToQueue {
  func launch() {
  let serialQueue = dispatch_queue_create(“com.example.MySerialQueue”, nil)
  dispatch_async(serialQueue, {
  print(“Task in the queue.。.”)
  })
  dispatch_async_f(serialQueue, unsafeBitCast(0, UnsafeMutablePointer《Int》.self), taskFunction())
  sleep(3)
  }
  func taskFunction() -》 dispatch_function_t {
  return { context in
  print(“Do some work with context.。.”)
  }
  }
  }
  let addTaskToQueue = AddTaskToQueue()
  addTaskToQueue.launch()
  除了這兩個(gè)函數(shù),我們還可以使用dispatch_sync和dispatch_sync_f函數(shù)同步的向隊(duì)列中添加任務(wù),并且我們要等待直到任務(wù)執(zhí)行完成。這兩個(gè)函數(shù)和上面的異步添加任務(wù)函數(shù)用法完全一致。
  那么什么時(shí)候用異步什么時(shí)候用同步呢,大多數(shù)情況下我們都是在主線程中使用GCD分派任務(wù),為了避免阻塞主線程,影響用戶體驗(yàn),所以通常情況下我們都使用異步添加任務(wù)的方式。當(dāng)然為了避免任務(wù)與主線程中產(chǎn)生資源競(jìng)爭(zhēng)的問題,有時(shí)候酌情也會(huì)使用同步添加任務(wù)的方式。
  Dispatch Queue的Completion Block
  還記得NSOperation的completionBlock屬性嗎,這個(gè)回調(diào)函數(shù)在任務(wù)執(zhí)行完成后調(diào)用,用于處理有些后續(xù)工作或者消息通知。在Dispatch Queue中并沒有類似的屬性,但是我們可以通過其他方式來實(shí)現(xiàn)。舉一個(gè)很常見的應(yīng)用場(chǎng)景,我們?cè)谥骶€程中分派一個(gè)下載圖片的任務(wù),讓其在二級(jí)線程中執(zhí)行,當(dāng)圖片下載完成后通知主線程,并由主線程將圖片顯示出來,我們看看簡(jiǎn)單的代碼片段:
  class DownloadImage {
  func dispatchTaskInMainThread() {
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), downloadImage())
  }
  func downloadImage() -》 (() -》 ()) {
  return {
  print(“Downloading image in \(NSThread.currentThread())”)
  dispatch_async(dispatch_get_main_queue()) {
  print(“Handle image and display in \(NSThread.currentThread())”)
  }
  }
  }
  }
  我們來看看上面代碼都做了些什么,首先在dispatchTaskInMainThread方法中,我們使用dispatch_get_global_queue函數(shù)獲取到全局并發(fā)隊(duì)列,然后將downloadImage下載圖片的方法作為任務(wù)添加到該全局隊(duì)列中。在downloadImage方法里,當(dāng)圖片下載完成后通過dispatch_get_main_queue函數(shù)獲取到主隊(duì)列,也就是在主線程中對(duì)圖片進(jìn)行處理,這樣我們就達(dá)到了Completion Block的效果。
  在隊(duì)列中循環(huán)執(zhí)行任務(wù)
  在我們的日常開發(fā)中,經(jīng)常會(huì)使用到for循環(huán)來處理一些任務(wù),而且這些任務(wù)之間也并沒有先后順序的關(guān)聯(lián),每個(gè)任務(wù)相對(duì)比較獨(dú)立。遇到這種情況,我們可以用dispatch_apply或dispatch_apply_f函數(shù)讓任務(wù)在隊(duì)列中循環(huán)執(zhí)行,并且可以是并發(fā)執(zhí)行,這樣相比for循環(huán)的串行執(zhí)行要更加效率:
  // for循環(huán)
  let arr = [“Swift”, “Objective-C”, “Java”, “Delphi”, “C++”]
  for element in arr {
  print(“Handle element. the element is \(element)”)
  }
  // dispatch_apply
  dispatch_apply(arr.count, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)){ index in
  print(“Handle element. the element is \(arr[index])。 Current thread is \(NSThread.currentThread())”)
  }
  從上面示例代碼片段中可以看到,dispatch_apply函數(shù)有三個(gè)參數(shù),第一個(gè)參數(shù)是循環(huán)次數(shù),第二個(gè)參數(shù)是目標(biāo)隊(duì)列,第三個(gè)則是要執(zhí)行的閉包任務(wù),循環(huán)次數(shù)是該閉包的唯一參數(shù)。
  暫停和重啟隊(duì)列
  在Dispatch Queue執(zhí)行任務(wù)時(shí),如果我們想暫停隊(duì)列,可以使用dispatch_suspend函數(shù),重新讓隊(duì)列執(zhí)行任務(wù)可以使用dispatch_resume。這里要注意的是暫停隊(duì)列只是讓隊(duì)列暫時(shí)停止執(zhí)行下一個(gè)任務(wù),而不是中斷當(dāng)前正在執(zhí)行的任務(wù)。
  Dispatch Group的使用
  在實(shí)際開發(fā)中,為了提升性能我們或許會(huì)經(jīng)常使用dispatch_async異步的將任務(wù)添加進(jìn)隊(duì)列去執(zhí)行,但有些時(shí)候需要之前隊(duì)列中的多個(gè)任務(wù)都執(zhí)行完成之后,才能獲取到正確的或者說想要的結(jié)果供后續(xù)邏輯代碼使用,遇到這種情況,就可以使用Dispatch Group,將多個(gè)任務(wù)在隊(duì)列中歸為一個(gè)組,并可以使用dispatch_group_wait函數(shù)讓之后的邏輯代碼等待,直到該組的任務(wù)都執(zhí)行完成后再執(zhí)行。
  var count = 0
  let concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
  dispatch_async(concurrentQueue) {
  print(“Task1 in dispatchGroup.。.”)
  sleep(2)
  count += 1
  }
  dispatch_async(concurrentQueue) {
  print(“Task2 in dispatchGroup.。.”)
  sleep(3)
  count += 1
  }
  dispatch_async(concurrentQueue) {
  print(“Task3 in dispatchGroup.。.”)
  sleep(1)
  count += 1
  }
  print(“I expect the count is 3, and the factual count is \(count)”)
  上面的代碼片段就是我剛才描述的場(chǎng)景,因?yàn)槭褂玫氖遣l(fā)隊(duì)列,也不好在每個(gè)任務(wù)里進(jìn)行回調(diào)處理,所以我們永遠(yuǎn)不會(huì)得到正確的count。如果我們使用Dispatch Group事情就簡(jiǎn)單多了:
  var count = 0
  let concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
  let dispatchGroup = dispatch_group_create()
  dispatch_group_async(dispatchGroup, concurrentQueue) {
  print(“Task1 in dispatchGroup.。.”)
  sleep(2)
  count += 1
  }
  dispatch_group_async(dispatchGroup, concurrentQueue) {
  print(“Task2 in dispatchGroup.。.”)
  sleep(3)
  count += 1
  }
  dispatch_group_async(dispatchGroup, concurrentQueue) {
  print(“Task3 in dispatchGroup.。.”)
  sleep(1)
  count += 1
  }
  dispatch_group_wait(dispatchGroup, DISPATCH_TIME_FOREVER)
  print(“I expect the count is 3, and the factual count is \(count)”)
  上面的代碼中,先使用dispatch_group_create函數(shù)創(chuàng)建Dispatch Group,然后使用dispatch_group_async函數(shù)將任務(wù)分進(jìn)組里,然后再添加進(jìn)隊(duì)列中。該函數(shù)有三個(gè)參數(shù),分別是Dispatch Group、Dispatch Queue和要執(zhí)行任務(wù)的閉包。當(dāng)添加完任務(wù)后使用dispatch_group_wait函數(shù)等待,直到指定組的任務(wù)全部完成,才會(huì)繼續(xù)執(zhí)行后面的打印語句,該函數(shù)有兩個(gè)參數(shù),第一個(gè)是目標(biāo)組,第二個(gè)是等待時(shí)間DISPATCH_TIME_NOW或DISPATCH_TIME_FOREVER。
  Dispatch Source
  前面的文章中介紹過Dispatch Source:
  Dispatch Source是GCD中的一個(gè)基本類型,從字面意思可稱為調(diào)度源,它的作用是當(dāng)有一些特定的較底層的系統(tǒng)事件發(fā)生時(shí),調(diào)度源會(huì)捕捉到這些事件,然后可以做其他的邏輯處理,調(diào)度源有多種類型,分別監(jiān)聽對(duì)應(yīng)類型的系統(tǒng)事件。我們來看看它都有哪些類型:
  Timer Dispatch Source:定時(shí)調(diào)度源。
  Signal Dispatch Source:監(jiān)聽UNIX信號(hào)調(diào)度源,比如監(jiān)聽代表掛起指令的SIGSTOP信號(hào)。
  Deor Dispatch Source:監(jiān)聽文件相關(guān)操作和Socket相關(guān)操作的調(diào)度源。
  Process Dispatch Source:監(jiān)聽進(jìn)程相關(guān)狀態(tài)的調(diào)度源。
  Mach port Dispatch Source:監(jiān)聽Mach相關(guān)事件的調(diào)度源。
  Custom Dispatch Source:監(jiān)聽自定義事件的調(diào)度源。
  這一節(jié)就來看看如何使用Dispatch Source。
  用通俗一點(diǎn)的話說就是用GCD的函數(shù)指定一個(gè)希望監(jiān)聽的系統(tǒng)事件類型,再指定一個(gè)捕獲到事件后進(jìn)行邏輯處理的閉包或者函數(shù)作為回調(diào)函數(shù),然后再指定一個(gè)該回調(diào)函數(shù)執(zhí)行的Dispatch Queue即可,當(dāng)監(jiān)聽到指定的系統(tǒng)事件發(fā)生時(shí)會(huì)調(diào)用回調(diào)函數(shù),將該回調(diào)函數(shù)作為一個(gè)任務(wù)放入指定的隊(duì)列中執(zhí)行。也就是說當(dāng)監(jiān)聽到系統(tǒng)事件后就會(huì)觸發(fā)一個(gè)任務(wù),并自動(dòng)將其加入隊(duì)列執(zhí)行,這里與之前手動(dòng)添加任務(wù)的模式不同,一旦將Diaptach Source與Dispatch Queue關(guān)聯(lián)后,只要監(jiān)聽到系統(tǒng)事件,Dispatch Source就會(huì)自動(dòng)將任務(wù)(回調(diào)函數(shù))添加到關(guān)聯(lián)的隊(duì)列中。
  有些時(shí)候回調(diào)函數(shù)執(zhí)行的時(shí)間較長(zhǎng),在這段時(shí)間內(nèi)Dispatch Source又監(jiān)聽到多個(gè)系統(tǒng)事件,理論上就會(huì)形成事件積壓,但好在Dispatch Source有很好的機(jī)制解決這個(gè)問題,當(dāng)有多個(gè)事件積壓時(shí)會(huì)根據(jù)事件類型,將它們進(jìn)行關(guān)聯(lián)和結(jié)合,形成一個(gè)新的事件。
  監(jiān)聽事件類型
  Dispatch Source一共可以監(jiān)聽六類事件,分為11個(gè)類型,我們來看看都是什么:
  DISPATCH_SOURCE_TYPE_DATA_ADD:屬于自定義事件,可以通過dispatch_source_get_data函數(shù)獲取事件變量數(shù)據(jù),在我們自定義的方法中可以調(diào)用dispatch_source_merge_data函數(shù)向Dispatch Source設(shè)置數(shù)據(jù),下文中會(huì)有詳細(xì)的演示。
  DISPATCH_SOURCE_TYPE_DATA_OR:屬于自定義事件,用法同上面的類型一樣。
  DISPATCH_SOURCE_TYPE_MACH_SEND:Mach端口發(fā)送事件。
  DISPATCH_SOURCE_TYPE_MACH_RECV:Mach端口接收事件。
  DISPATCH_SOURCE_TYPE_PROC:與進(jìn)程相關(guān)的事件。
  DISPATCH_SOURCE_TYPE_READ:讀文件事件。
  DISPATCH_SOURCE_TYPE_WRITE:寫文件事件。
  DISPATCH_SOURCE_TYPE_VNODE:文件屬性更改事件。
  DISPATCH_SOURCE_TYPE_SIGNAL:接收信號(hào)事件。
  DISPATCH_SOURCE_TYPE_TIMER:定時(shí)器事件。
  DISPATCH_SOURCE_TYPE_MEMORYPRESSURE:內(nèi)存壓力事件。
  創(chuàng)建Dispatch Source
  我們可以使用dispatch_source_create函數(shù)創(chuàng)建Dispatch Source,該函數(shù)有四個(gè)參數(shù):
  type:第一個(gè)參數(shù)用于標(biāo)識(shí)Dispatch Source要監(jiān)聽的事件類型,共有11個(gè)類型。
  handle:第二個(gè)參數(shù)是取決于要監(jiān)聽的事件類型,比如如果是監(jiān)聽Mach端口相關(guān)的事件,那么該參數(shù)就是mach_port_t類型的Mach端口號(hào),如果是監(jiān)聽事件變量數(shù)據(jù)類型的事件那么該參數(shù)就不需要,設(shè)置為0就可以了。
  mask:第三個(gè)參數(shù)同樣取決于要監(jiān)聽的事件類型,比如如果是監(jiān)聽文件屬性更改的事件,那么該參數(shù)就標(biāo)識(shí)文件的哪個(gè)屬性,比如DISPATCH_VNODE_RENAME。
  queue:第四個(gè)參數(shù)設(shè)置回調(diào)函數(shù)所在的隊(duì)列。
  let dispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
  let dispatchSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatchQueue)
  上面的代碼就是創(chuàng)建Dispatch Source的簡(jiǎn)單示例。
  設(shè)置事件處理器
  前文中提到過,當(dāng)Dispatch Source監(jiān)聽到事件時(shí)會(huì)調(diào)用指定的回調(diào)函數(shù)或閉包,該回調(diào)函數(shù)或閉包就是Dispatch Source的事件處理器。我們可以使用dispatch_source_set_event_handler或dispatch_source_set_event_handler_f函數(shù)給創(chuàng)建好的Dispatch Source設(shè)置處理器,前者是設(shè)置閉包形式的處理器,后者是設(shè)置函數(shù)形式的處理器:
  dispatch_source_set_event_handler(dispatchSource, {
  print(“Dispatch Source 事件處理器。..”)
  })
  // 根據(jù)閉包尾隨的特性,還可以有下面的寫法
  dispatch_source_set_event_handler(dispatchSource) {
  print(“Dispatch Source 事件處理器。..”)
  }
  從上面示例代碼中可以看到,該函數(shù)有兩個(gè)參數(shù),第一個(gè)是設(shè)置目標(biāo)Dispatch Source,第二個(gè)參數(shù)就是設(shè)置處理器了。
  既然是事件處理器,那么肯定需要獲取一些Dispatch Source的信息,GCD提供了三個(gè)在處理器中獲取Dispatch Source相關(guān)信息的函數(shù),比如handle、mask。而且針對(duì)不同類型的Dispatch Source,這三個(gè)函數(shù)返回?cái)?shù)據(jù)的值和類型都會(huì)不一樣,下面來看看這三個(gè)函數(shù):
  dispatch_source_get_handle:這個(gè)函數(shù)用于獲取在創(chuàng)建Dispatch Source時(shí)設(shè)置的第二個(gè)參數(shù)handle。
  如果是讀寫文件的Dispatch Source,返回的就是描述符。
  如果是信號(hào)類型的Dispatch Source,返回的是int類型的信號(hào)數(shù)。
  如果是進(jìn)程類型的Dispatch Source,返回的是pid_t類型的進(jìn)程id。
  如果是Mach端口類型的Dispatch Source,返回的是mach_port_t類型的Mach端口。
  dispatch_source_get_data:該函數(shù)用于獲取Dispatch Source監(jiān)聽到事件的相關(guān)數(shù)據(jù)。
  如果是讀文件類型的Dispatch Source,返回的是讀到文件內(nèi)容的字節(jié)數(shù)。
  如果是寫文件類型的Dispatch Source,返回的是文件是否可寫的標(biāo)識(shí)符,正數(shù)表示可寫,負(fù)數(shù)表示不可寫。
  如果是監(jiān)聽文件屬性更改類型的Dispatch Source,返回的是監(jiān)聽到的有更改的文件屬性,用常量表示,比如DISPATCH_VNODE_RENAME等。
  如果是進(jìn)程類型的Dispatch Source,返回監(jiān)聽到的進(jìn)程狀態(tài),用常量表示,比如DISPATCH_PROC_EXIT等。
  如果是Mach端口類型的Dispatch Source,返回Mach端口的狀態(tài),用常量表示,比如DISPATCH_MACH_SEND_DEAD等。
  如果是自定義事件類型的Dispatch Source,返回使用dispatch_source_merge_data函數(shù)設(shè)置的數(shù)據(jù)。
  dispatch_source_get_mask:該函數(shù)用于獲取在創(chuàng)建Dispatch Source時(shí)設(shè)置的第三個(gè)參數(shù)mask。在進(jìn)程類型,文件屬性更改類型,Mach端口類型的Dispatch Source下該函數(shù)返回的結(jié)果與dispatch_source_get_data一樣。
  注冊(cè)Cancellation Handler
  Cancellation Handler就是當(dāng)Dispatch Source被釋放時(shí)用來處理一些后續(xù)事情,比如關(guān)閉文件描述符或者釋放Mach端口等。我們可以使用dispatch_source_set_cancel_handler函數(shù)或者dispatch_source_set_cancel_handler_f函數(shù)給Dispatch Source注冊(cè)Cancellation Handler:
  dispatch_source_set_cancel_handler(dispatchSource) {
  print(“進(jìn)行善后處理。..”)
  }
  該函數(shù)有兩個(gè)參數(shù),第一個(gè)參數(shù)是目標(biāo)Dispatch Source,第二個(gè)參數(shù)就是要進(jìn)行善后處理的閉包或者函數(shù)。
  更改Dispatch Source的目標(biāo)隊(duì)列
  在上文中,我們說過可以使用dispatch_source_create函數(shù)創(chuàng)建Dispatch Source,并且在創(chuàng)建時(shí)會(huì)指定回調(diào)函數(shù)執(zhí)行的隊(duì)列,那么如果事后想更改隊(duì)列,比如說想更改隊(duì)列的優(yōu)先級(jí),這時(shí)我們可以使用dispatch_set_target_queue函數(shù)實(shí)現(xiàn):
  let dispatchQueueDefaultPriority = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
  let dispatchSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatchQueueDefaultPriority)
  let dispatchQueueLowPriority = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)
  dispatch_set_target_queue(dispatchSource, dispatchQueueLowPriority)
  這里需要注意的是,如果在更改目標(biāo)隊(duì)列時(shí),Dispatch Source已經(jīng)監(jiān)聽到相關(guān)事件,并且回調(diào)函數(shù)已經(jīng)在之前的隊(duì)列中執(zhí)行了,那么會(huì)一直在舊的隊(duì)列中執(zhí)行完成,不會(huì)轉(zhuǎn)移到新的隊(duì)列中去。
  暫?;謴?fù)Dispatch Source
  暫停和恢復(fù)Dispatch Source與Dispatch Queue一樣,都適用dispatch_suspend和dispatch_resume函數(shù)。這里需要注意的是剛創(chuàng)建好的Dispatch Source是處于暫停狀態(tài)的,所以使用時(shí)需要用dispatch_resume函數(shù)將其啟動(dòng)。
  廢除Dispatch Source
  如果我們不再需要使用某個(gè)Dispatch Source時(shí),可以使用dispatch_source_cancel函數(shù)廢除,該函數(shù)只有一個(gè)參數(shù),那就是目標(biāo)Dispatch Source。
  Dispatch Source實(shí)踐
  說了這么多,這一節(jié)來看看Dispatch Source到底怎么用。
  用Dispatch Source監(jiān)聽定時(shí)器
  Dispatch Source能監(jiān)聽的事件中有一個(gè)類型就是定時(shí)器,我們來看看如何實(shí)現(xiàn):
  class TestDispatchSource {
  func launch() {
  let dispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
  let timer = createTimerDispatchSource(dispatch_time(DISPATCH_TIME_NOW, 0), interval: NSEC_PER_SEC * 5, leeway: 0, queue: dispatchQueue) {
  print(“處理定時(shí)任務(wù),該任務(wù)每5秒執(zhí)行一次。..”)
  }
  dispatch_resume(timer)
  sleep(30)
  }
  func createTimerDispatchSource(startTime: dispatch_time_t, interval: UInt64, leeway: UInt64, queue: dispatch_queue_t, handler: dispatch_block_t) -》 dispatch_source_t {
  let timerDispatchSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue)
  dispatch_source_set_timer(timerDispatchSource, startTime, interval, leeway)
  dispatch_source_set_event_handler(timerDispatchSource, handler)
  return timerDispatchSource
  }
  }
  上面的代碼示例中一個(gè)新的函數(shù)dispatch_source_set_timer,該函數(shù)的作用就是給監(jiān)聽事件類型為DISPATCH_SOURCE_TYPE_TIMER的Dispatch Source設(shè)置相關(guān)屬性,該函數(shù)有四個(gè)參數(shù):
  source:該參數(shù)為目標(biāo)Dispatch Source,類型為dispatch_source_t.
  start:該參數(shù)為定時(shí)器的起始時(shí)間,類型為dispatch_time_t。
  interval:該參數(shù)為定時(shí)器的間隔時(shí)間,類型為UInt64,間隔時(shí)間的單位是納秒。
  leeway:該參數(shù)為間隔時(shí)間的精度,類型為UInt64,時(shí)間單位也是納秒。
  用Dispatch Source監(jiān)聽自定義事件
  Dispatch Source能監(jiān)聽的事件中有一個(gè)類型是自定義事件,下面我們來看看如何使用:
  class TestDispatchSource {
  func launch() {
  var totalProcess = 0
  let dispatchSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_ADD, 0, 0, dispatch_get_main_queue())
  dispatch_source_set_event_handler(dispatchSource) {
  let process = dispatch_source_get_data(dispatchSource)
  totalProcess += Int(process)
  print(“這里可以在主線程更新UI,顯示進(jìn)度條。..進(jìn)度為\(totalProcess)%”)
  }
  dispatch_resume(dispatchSource)
  generateCustomEvent(dispatchSource)
  }
  func generateCustomEvent(dispatchSource: dispatch_source_t) {
  let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
  for index in 0.。.100 {
  dispatch_sync(queue) {
  print(“模擬自定義事件。..進(jìn)度為\(index)%”)
  dispatch_source_merge_data(dispatchSource, 1)
  sleep(2)
  }
  }
  }
  }
  我們來看看generateCustomEvent(dispatchSource: dispatch_source_t)方法,該方法的作用的是模擬自定義事件,首先創(chuàng)建一個(gè)全局并發(fā)隊(duì)列,然后循環(huán)讓其執(zhí)行任務(wù),在執(zhí)行的任務(wù)里調(diào)用dispatch_source_merge_data函數(shù),就可以觸發(fā)監(jiān)聽類型為DISPATCH_SOURCE_TYPE_DATA_ADD或者DISPATCH_SOURCE_TYPE_DATA_OR的Dispatch Source。該函數(shù)有兩個(gè)參數(shù),第一個(gè)參數(shù)是目標(biāo)Dispatch Source,第二個(gè)參數(shù)的類型是無符號(hào)長(zhǎng)整型,用于向目標(biāo)Dispatch Source中的對(duì)應(yīng)變量追加指定的數(shù)。
  我們?cè)賮砜纯慈绾伪O(jiān)聽自定義時(shí)間,首先創(chuàng)建類型為DISPATCH_SOURCE_TYPE_DATA_ADD的Dispatch Source,然后設(shè)置回調(diào)閉包,在閉包中使用dispatch_source_get_data獲取追加的變量值,該函數(shù)只有一個(gè)參數(shù),就是目標(biāo)Dispatch Source,這里需要注意的是通過dispatch_source_get_data函數(shù)獲取的變量值并不是累加值,而是每次調(diào)用dispatch_source_merge_data函數(shù)時(shí)設(shè)置的值,所以在上面的示例中用totalProcess變量累加每次獲取到的值。
  上面的示例可以用來模擬后臺(tái)進(jìn)行下載,根據(jù)下載的數(shù)據(jù)量使用dispatch_source_merge_data函數(shù)給目標(biāo)Dispatch Source設(shè)置相應(yīng)的變量值,然后在主線程中監(jiān)聽到Dispatch Source的自定義事件,通過dispatch_source_get_data函數(shù)獲取到變量,用于更新顯示進(jìn)度條的UI。
?

非常好我支持^.^

(0) 0%

不好我反對(duì)

(0) 0%

Dispatch Queue任務(wù)執(zhí)行與Dispatch Source下載

相關(guān)電子資料下載

      發(fā)表評(píng)論

      用戶評(píng)論
      評(píng)價(jià):好評(píng)中評(píng)差評(píng)

      發(fā)表評(píng)論,獲取積分! 請(qǐng)遵守相關(guān)規(guī)定!

      ?