1. 程式人生 > >【iOS】Swift4.0 GCD的使用筆記

【iOS】Swift4.0 GCD的使用筆記

前言

在Swift4.0版本中GCD的常用方法還是有比較大的改動,這裡做個簡單的整理彙總。

GCD的佇列

佇列是一種遵循先進先出(FIFO)原則的資料結構,是一種特殊的線性表。

主佇列 全域性佇列 序列佇列 並行佇列
同步 X 並行同步 串行同步
非同步 序列非同步 並行非同步 序列非同步

X 表示禁止這麼使用,—— 表示不建議這麼使用。

1. 主佇列

主佇列預設是序列的,另外主佇列不能結合同步函式(sync)使用,會造成執行緒死鎖。

override func viewDidLoad() {
      super.viewDidLoad()
      // Do
any additional setup after loading the view, typically from a nib. let mainQueue = DispatchQueue.main mainQueue.sync { print("造成當前執行緒:\(Thread.current)死鎖") } }

同時主佇列中不應該新增耗時的任務,因為系統的UI相關事務都是在主執行緒佇列中完成的,大量大耗時操作可能會造成卡頓,應該避免。

主佇列最常用的方法是當子執行緒需要通知主執行緒做一些UI上面的操作時,結合子執行緒使用:

let
queue = DispatchQueue(label: "com.roki.thread") queue.async { // 大量耗時操作 print("大量耗時操作執行緒:\(Thread.current)") Thread.sleep(forTimeInterval: 2) DispatchQueue.main.async { //回到主執行緒操作UI print("回到主執行緒:\(Thread.current)") } }

DF993F5D-6A1D-4869-A7E8-5E9D871915D8.png

2. 全域性佇列

全域性佇列是由系統建立的,預設是並行的。全域性佇列具體執行在哪一個執行緒,是由系統維護一個執行緒池,然後挑選其中的一至多條執行緒來使用。哪條執行緒會被使用是未知的,是由系統根據當前的併發任務,處理器的負載等情況來決定的。

  • 全域性併發同步佇列
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    for i in 1...10 {
        DispatchQueue.global().sync {
            //全域性併發同步
            Thread.sleep(forTimeInterval: 2)
            print("執行緒\(Thread.current)正在執行\(i)號任務")
        }
    }
}

9C11F7B3-7602-4E3B-94A2-0255DFC77077.png

從終端輸出我們可以知道任務被順序執行了,這是因為雖然當前是一個併發佇列,但是是同步執行的。同步操作會使得在前一個任務完成後才去執行下一個任務。同步與非同步的區別還在於它不會建立新的執行緒,而是直接在當前執行緒中執行了相關的任務,當前執行緒是主執行緒。同步會阻塞當前執行緒。

  • 全域性併發非同步佇列
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    for i in 1...10 {
        DispatchQueue.global().async {
            //全域性併發非同步
            Thread.sleep(forTimeInterval: 2)
            print("執行緒\(Thread.current)正在執行\(i)號任務")
        }
    }
}

7D63F60B-3DC4-4071-854E-CCB3E36019E4.png

從終端輸出我們可以知道任務被隨機執行了,而且被分配在多個子執行緒中執行的,這符合併發的本質。另外需要注意的是全域性併發非同步佇列,系統在挑選來執行任務的執行緒的時候,會挑選除了主執行緒之外的其他執行緒。

3. 自定義佇列

除了上述佇列之外,我們還可以使用DispatchQueue建立自定義的佇列。
let queue = DispatchQueue(label: "com.roki.thread")
需要注意的是上述建立自定義佇列的方式,預設建立的是序列佇列。
還有一種建立自定義佇列的方法是:

let queue = DispatchQueue(label: "com.custom.thread", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent)

iOS10.0 之後上述API更新為:

let queue = DispatchQueue(label: "com.custom.thread", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent, autoreleaseFrequency: .workItem, target: nil)

引數說明:
1. label 表示佇列標籤
2. qos 表示設定佇列的優先順序
- .userInteractive 需要使用者互動的,優先順序最高,和主執行緒一樣
- .userInitiated 即將需要,使用者期望優先順序,優先順序高比較高
- .default 預設優先順序
- .utility 需要執行一段時間後,再通知使用者,優先順序低
- *.background 後臺執行的,優先順序比較低
- *.unspecified 不指定優先順序,最低
3. attributes 表示佇列型別,預設為序列佇列,設定為.concurrent表示並行佇列。iOS 10.0之後 attributes 新增.initiallyInactive屬性表示當前佇列是不活躍的,它需要呼叫DispatchQueueactivate方法來執行任務。
4. autoreleaseFrequency 表示自動釋放頻率,設定自動釋放機制。
- .inherit 表示不確定,之前預設的行為也是現在的預設值
- .workItem 表示為每個執行的專案建立和排除自動釋放池, 專案完成時清理臨時物件
- .never 表示GCD不為您管理自動釋放池

  • 同步序列佇列
    其實同步序列佇列,沒什麼意思的,不管是同步操作還是序列操作都會導致任務被一個一個的執行。這個操作尤其是在主執行緒執行的時候需要注意,避免造成執行緒的卡頓。
let queue = DispatchQueue(label: "com.custom.thread")
queue.sync {
   //同步序列佇列
}
  • 非同步序列佇列
    因為是序列佇列,即使是非同步執行的,任務也是按照順序依次執行的,但是在子執行緒中執行的。
let queue = DispatchQueue(label: "com.custom.thread")
queue.async {
   //非同步序列佇列
}

9D774A76-4F71-49AE-903A-57741B89D1DE.png

根據iOS10.0 之後attributes新增的.initiallyInactive屬性,我們可以建立不活躍佇列。
- 同步序列不活躍佇列

let queue = DispatchQueue(label: "com.custom.thread", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.initiallyInactive, autoreleaseFrequency: .workItem, target: nil)
queue.sync {
   //同步序列不活躍佇列
}
queue.activate()
  • 非同步並行不活躍佇列
let queue = DispatchQueue(label: "com.custom.thread", qos: DispatchQoS.default, attributes: [.initiallyInactive, .concurrent], autoreleaseFrequency: .workItem, target: nil)
queue.async {
   //非同步並行不活躍佇列
}
queue.activate()
  • 同步並行佇列
    只要涉及到同步的,都不會開啟新執行緒,會在當前執行緒執行任務,同時任務只能依次執行。
let queue = DispatchQueue(label: "com.custom.thread", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent)
for i in 1...10 {
     queue.sync {
        //併發同步佇列
        Thread.sleep(forTimeInterval: 2)
        print("執行緒\(Thread.current)正在執行\(i)號任務")
     }
}

BC7AAE0B-C3FA-4AEB-9593-72E02D4A105F.png

  • 非同步並行佇列
    非同步並行佇列就會在多個執行緒中,隨機執行任務。
let queue = DispatchQueue(label: "com.custom.thread", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent)
for i in 1...10 {
     queue.async {
        //併發非同步
        Thread.sleep(forTimeInterval: 2)
        print("執行緒\(Thread.current)正在執行\(i)號任務")
     }
}

EA277C08-A7FF-49B5-B26B-73521A51C5CF.png

4. 任務組(DispatchGroup)

如果我們想監聽多個任務的執行情況,那麼我們需要將任務(非同步、同步、序列、並行)都新增到任務組中,然後通過DispatchGroupnotify函式就可以監聽是否組內任務都已經完成。

let group = DispatchGroup()
let queue = DispatchQueue(label: "com.custom.thread", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent)
for i in 1...10 {
    queue.async(group: group) {
       //併發非同步
       Thread.sleep(forTimeInterval: 2)
       print("執行緒\(Thread.current)正在執行\(i)號任務")
   }
}

group.notify(queue: DispatchQueue.main) {
     // 通知主執行緒,子執行緒操作已完成
     print("所有任務都已經完成")
}

05A6287E-81AC-49A0-A277-D53994DB8E0A.png

5. 任務物件(DispatchWorkItem)

在Swift4.0 中使用DispatchWorkItem代替原來OC中的dispatch_block_t。 在DispatchQueue執行操作,除了直接傳了一個() -> Void 型別的閉包外,還可以傳入一個DispatchWorkItem任務物件。DispatchWorkItem的初始化方法可以配置QosDispatchWorkItemFlags,但是這兩個引數都有預設引數,所以也可以只傳入一個閉包。
DispatchWorkItemFlags列舉中assignCurrentContext表示QoS根據建立時的context決定。 值得一提的是DispatchWorkItem也有wait方法,使用方式和DispatchGroup一樣。呼叫會等待這個workItem執行完。

let queue = DispatchQueue(label: "com.custom.thread", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent)
let workItem = DispatchWorkItem {
     Thread.sleep(forTimeInterval: 2)
     print("執行緒\(Thread.current)正在執行任務")
}
queue.async(execute: workItem)

print("before waiting")
workItem.wait()
print("after waiting")

A25890FA-C5B3-4000-94D1-D00044663A1A.png

相關推薦

iOSSwift4.0 GCD的使用筆記

前言 在Swift4.0版本中GCD的常用方法還是有比較大的改動,這裡做個簡單的整理彙總。 GCD的佇列 佇列是一種遵循先進先出(FIFO)原則的資料結構,是一種特殊的線性表。 主佇列 全域性佇列 序列佇列 並行佇列

MySQLMySQL8.0.13 騷操作速查筆記——專治各種忘詞水土不服

1、前言   【Linux】【MySQL】CentOS7安裝最新版MySQL8.0.13(最新版MySQL從安裝到執行)   專治各種忘詞,各種水土不服。   - -,就是一個健忘貴的速查表;(當然不包括SQL的基礎語句啥的) 2、開始 -- 登入sys資料庫 mysql -u root -

iOS第02講 多執行緒NSThread/GCD/RunLoop/NSTimer/Socket資料傳輸

一、NSThread       1.1 基本使用 -(void) createThread{               //NSThread   &nb

iOSSafe Area Layout Guide before iOS 9.0

iPhoneX馬上快要預售了,齊劉海的小發型還是夠屌屌的。今天升級完Xcode9, 開啟Xcode順手編譯的了一下工程結果報錯了!差Xcode這麼不給面子,看了下錯誤資訊“Safe Area Layout Guide before iOS 9.0”,“Safe

Asp.net MVC4.0學習筆記找不到DbContext和無法檢索元資料

編譯環境:Visual Studio 2012; 解決問題:找不到DbContext需要安裝EntityFramework,安裝方法如下:      工具->庫程式包管理器->程式包管理器控制檯,開啟控制檯後,輸入命令Install-package Ent

iOS代理傳值與塊代碼傳值

ring 方法 nslog 設置代理 轉載 adf delegate alloc 代理傳值 主線程與子線程常常須要進行數據的傳遞。不同的類之間,不同的控制器之間都須要。 並且常常須要監聽一個動作的完畢。而後才去做對應事件。(代理是一對一的關系)。 一、代理傳值 代理

iOSUICollectionView自己定義Layout之蜂窩布局

with top http reserve src 布局 step object .com 網上的UICollectionView的Layout布局,其cell的形狀多為矩形和圓形。 本篇博文將正六邊形作為cell的基本形狀,為您展現獨特的蜂窩布局效果及實現源代碼。 幫

iOSUIDynamicAnimator動畫

set translate logs enc ica cgpoint isp mat .cn 創建動畫 1 UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:sel

16vuex2.0 之 getter

this map 多個參數 name not 同時 方便 比較 compute  有的組件中獲取到 store 中的state, 需要對進行加工才能使用,computed 屬性中就需要寫操作函數,如果有多個組件中都需要進行這個操作,那麽在各個組件中都寫相同的函數,那就非常

15vuex2.0 之 modules

his 來看 暴露 方式 ets 我們 spa web space   vue 使用的是單一狀態樹對整個應用的狀態進行管理,也就是說,應用中的所有狀態都放到store中,如果是一個大型應用,狀態非常多, store 就會非常龐大,不太好管理。這時vuex 提供了另外一種方式

BZOJ4052[Cerc2013]Magical GCD 亂搞

cnblogs cpp name 直接 bzoj4052 scrip des ons ostream 【BZOJ4052】[Cerc2013]Magical GCD Description 給出一個長度在 100 000 以內的正整數序列,大小不超過 10^12。

轉載CentOS7.0下安裝Telnet

soc nbsp 裝包 正常 system 關閉防火墻 blog 不能 service 1.、先檢查CentOS7.0是否已經安裝以下兩個安裝包:telnet-server、xinetd。命令如下: # rpm -qa telnet-server # rpm -qa xin

轉載.NET Remoting學習筆記(一)概念

leg false 情況下 system 版權 while 對象模式 無需 new 目錄 .NET Remoting學習筆記(一)概念 .NET Remoting學習筆記(二)激活方式 .NET Remoting學習筆記(三)信道 背景 自接觸編程以來,一直聽過這個名

轉載.NET Remoting學習筆記(三)信道

star fig cati 服務端 pro net string spa 處理類型 目錄 .NET Remoting學習筆記(一)概念 .NET Remoting學習筆記(二)激活方式 .NET Remoting學習筆記(三)信道 參考:♂風車車.Net .NET Fra

bzoj2820YY的GCD 莫比烏斯反演

spa tex 給定 void fin include ans iostream while YY的GCD Description 神犇YY虐完數論後給傻×kAc出了一題 給定N, M,求1<=x<=N, 1<=y<=M且g

24Python裝飾器筆記

put 訪問 img elif 分享 sse pass 源代碼 local 裝飾器定義:本職是函數,(裝飾其他函數)就是為其他函數添加附加功能。原則:1.不能修改被裝飾的函數的源代碼2.不能修改被裝飾函數的調用的方式 先來一個直觀感受 import time def tim

WIPSwift4 函數

tro strong 任務表 元組 width log class spa pan 創建: 2018/02/19 【任務表】TODO 函數定義的基礎

WIPSwift4 構造體

div tab table width font post ont 索引 style 創建: 2018/02/19 【任務表】TODO 構造體定義

原創Java面試題筆記

也不能 als color body 但是 函數 log 字符 方法 自動裝箱、拆箱 1 public class IntegerTest { 2 3 @Test 4 public void constPool(){ 5

WIPSwift4 可選值

任務 order pan width tab wid ont 可選值 div 創建: 2018/02/25 【任務表】TODO 可選型