GCD-Swift 3 高級用法

當(dāng)今App中多線程是必不可少的因素给梅,而GCD起著舉足輕重的作用。
下面我們來看看swift 3.0中的GCD瓢娜,能給我們帶來哪些驚喜吧识窿!

dispatch_async

GCD最常用的模式就是在全局隊列執(zhí)行任務(wù)主線程中刷新UI

DispatchQueue.global(qos: .default).async {
    
    print("task" + "\(Thread.current)")
    
    //主線程異步執(zhí)行 刷新UI
    DispatchQueue.main.async {
        print("UI - task" + "\(Thread.current) ")
    }
}

Queue attributes

由于.serial不在是DispatchQueue.Attributes中的屬性,只留下.concurrent第步。下面我們通過代碼驗證一下

//創(chuàng)建并發(fā)隊列
let concurrentQueue = DispatchQueue(label: "mkiltech.com",attributes: .concurrent)
//創(chuàng)建串行隊列
let serialQueue = DispatchQueue(label: "mkiltech.com")

//串行異步
serialQueue.async {
    sleep(2)
    print("serialTask 1" + "\(Thread.current) ")
}
serialQueue.async {
    print("serialTask 2" + "\(Thread.current) ")
}

//并發(fā)異步
concurrentQueue.async {
    sleep(2)
    print("concurrentTask 1" + "\(Thread.current) ")
}
concurrentQueue.async {
    print("concurrentTask 2" + "\(Thread.current) ")
}

// 打印結(jié)果
concurrentTask 2<NSThread: 0x60800007d640>{number = 3, name = (null)} 
concurrentTask 1<NSThread: 0x60800007e340>{number = 4, name = (null)} 
serialTask 1<NSThread: 0x600000078f00>{number = 5, name = (null)} 
serialTask 2<NSThread: 0x600000078f00>{number = 5, name = (null)} 

可以看出疮装,默認(rèn)情況下創(chuàng)建的是串行隊列,指定.concurrent為并發(fā)隊列粘都。

下面來看看隊列完整的初始化方法

 public convenience init(label: String, qos: DispatchQoS = default, attributes: DispatchQueue.Attributes = default, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency = default, target: DispatchQueue? = default)

@param qos 隊列優(yōu)先級
新的隊列優(yōu)先級替換了在iOS8中被廢棄的舊的優(yōu)先級屬性,顯得更加直觀友好,這是在 QOS中的調(diào)用列表:

 *  - DISPATCH_QUEUE_PRIORITY_HIGH:         QOS_CLASS_USER_INITIATED                   (.userInitiated)
 *  - DISPATCH_QUEUE_PRIORITY_DEFAULT:      QOS_CLASS_DEFAULT                          (.default)
 *  - DISPATCH_QUEUE_PRIORITY_LOW:          QOS_CLASS_UTILITY                          (.utility)
 *  - DISPATCH_QUEUE_PRIORITY_BACKGROUND:   QOS_CLASS_BACKGROUND                       (.background)

@param attributes 串行隊列并發(fā)隊列廓推,上面已說明
@param autoreleaseFrequency
下面是一段官方代碼注釋,由于沒有找到相關(guān)官方文檔說明翩隧,理解可能有偏差樊展。

    /*!
     * @typedef dispatch_autorelease_frequency_t
     * Values to pass to the dispatch_queue_attr_make_with_autorelease_frequency()
     * function.
     *
     * @const DISPATCH_AUTORELEASE_FREQUENCY_INHERIT
     * Dispatch queues with this autorelease frequency inherit the behavior from
     * their target queue. This is the default behavior for manually created queues.
     *
     * @const DISPATCH_AUTORELEASE_FREQUENCY_WORK_ITEM
     * Dispatch queues with this autorelease frequency push and pop an autorelease
     * pool around the execution of every block that was submitted to it
     * asynchronously.
     * @see dispatch_queue_attr_make_with_autorelease_frequency().
     *
     * @const DISPATCH_AUTORELEASE_FREQUENCY_NEVER
     * Dispatch queues with this autorelease frequency never set up an individual
     * autorelease pool around the execution of a block that is submitted to it
     * asynchronously. This is the behavior of the global concurrent queues.
     */
  public enum AutoreleaseFrequency {
        case inherit

        case workItem

        case never
    }

我們看到DispatchQueue.AutoreleaseFrequency有三種屬性值.inherit.workItem.never,稍微研究了一下GCDAutorelease
以前堆生,DispatchQueues將在未指定的時間(當(dāng)線程變?yōu)椴换顒訒r)彈出它們的自動釋放池专缠。 在實(shí)踐中,這意味著您為每個提交的調(diào)度項目創(chuàng)建了一個自動釋放池淑仆,或者您的自動釋放的對象將掛起不可預(yù)測的時間量涝婉。

非確定性不是什么好事情(特別是在并發(fā)庫!)蔗怠,所以現(xiàn)在Apple允許你指定三種行為之一:
.inherit:不確定墩弯,之前默認(rèn)的行為也是現(xiàn)在的默認(rèn)值
.workItem:為每個執(zhí)行的項目創(chuàng)建和排除自動釋放池,項目完成時清理臨時對象
.never:GCD不為您管理自動釋放池

DispatchTime 延時執(zhí)行

let delay = DispatchTime.now() + .seconds(60)
DispatchQueue.main.asyncAfter(deadline: delay) {
    // task 延時執(zhí)行
}

也可以直接+一個秒數(shù)

let two = DispatchTime.now() + 2.0

因為DispatchTime中自定義了這些運(yùn)算符吩跋。

public func +(time: DispatchWallTime, seconds: Double) -> DispatchWallTime
public func -(time: DispatchTime, interval: DispatchTimeInterval) -> DispatchTime
public func <(a: DispatchTime, b: DispatchTime) -> Bool
public func ==(a: DispatchTime, b: DispatchTime) -> Bool

DispatchGroup

如果想在dispatch_queue中所有的任務(wù)執(zhí)行完成后再做某種操作可以使用DispatchGroup。原先的dispatch_group_t由現(xiàn)在的DispatchGroup對象代替渔工。

let group = DispatchGroup()

let queueDownload1 = DispatchQueue(label: "com.Download1")
queueDownload1.async(group: group) {
    // up task 1
}

let queueDownload2 = DispatchQueue(label: "com.Download2")
queueDownload2.async(group: group) {
    // up task 2
}

group.notify(queue: DispatchQueue.main) {
    // 等待下載完成
}

DispatchGroup會在組里的操作都完成后執(zhí)行notify锌钮。

DispatchWorkItem

使用DispatchWorkItem代替原來的dispatch_block_t。 在DispatchQueue執(zhí)行操作除了直接傳了一個() -> Void
類型的閉包外引矩,還可以傳入一個DispatchWorkItem梁丘。

public func sync(execute workItem: DispatchWorkItem) 
public func async(execute workItem: DispatchWorkItem)

DispatchWorkItem的初始化方法可以配置QosDispatchWorkItemFlags,但是這兩個參數(shù)都有默認(rèn)參數(shù)旺韭,所以也可以只傳入一個閉包兰吟。

public init(qos: DispatchQoS = default, flags: DispatchWorkItemFlags = default, block: @escaping @convention(block) () -> ())

DispatchWorkItemFlags枚舉中assignCurrentContext表示QoS根據(jù)創(chuàng)建時的context決定。 值得一提的是DispatchWorkItem也有wait方法茂翔,使用方式和group一樣。調(diào)用會等待這個workItem執(zhí)行完履腋。

let myQueue = DispatchQueue(label: "mkil.queue", attributes: .concurrent)let workItem = DispatchWorkItem { sleep(1) print("done")}myQueue.async(execute: workItem)print("before waiting")workItem.wait()print("after waiting")

barrier

假設(shè)我們有一個并發(fā)的隊列用來讀寫一個數(shù)據(jù)對象珊燎。如果這個隊列里的操作是讀的,那么可以多個同時進(jìn)行遵湖。如果有寫的操作悔政,則必須保證在執(zhí)行寫入操作時,不會有讀取操作在執(zhí)行延旧,必須等待寫入完成后才能讀取谋国,否則就可能會出現(xiàn)讀到的數(shù)據(jù)不對。在之前我們用dipatch_barrier實(shí)現(xiàn)迁沫。 現(xiàn)在屬性放在了DispatchWorkItemFlags里芦瘾。

let wirte = DispatchWorkItem(flags: .barrier) { 
    // write data
}
let dataQueue = DispatchQueue(label: "data", attributes: .concurrent)
dataQueue.async(execute: wirte)

DispatchSemaphore

為了線程安全的統(tǒng)計數(shù)量,我們會使用信號量作計數(shù)集畅。原來的dispatch_semaphore_t現(xiàn)在用DispatchSemaphore對象表示近弟。 初始化方法只有一個,傳入一個Int類型的數(shù)挺智。

let semaphore = DispatchSemaphore(value: 5) 
// 信號量減一
semaphore.wait() 
//信號量加一
semaphore.signal()

dispatch_once

在Swift3中,dispatch_once被廢棄了,應(yīng)該被替換成了其他全局或者靜態(tài)變量和常量.

class MyManager {
    public static let shareInstance = MyManager()
}

let manager = MyManager.shareInstance

dispatch_assert

這個也是今年蘋果在OS發(fā)布的新技術(shù),線程的先決條件.這個在你執(zhí)行代碼前可以檢查當(dāng)前線程是否是你希望的線程.

enum DispatchPredicate {
//Predicates that the evaluated context is the associated dispatch queue.
case onQueue(DispatchQueue)

//Predicates that the evaluated context is the associated dispatch queue as part of a barrier operation.
case onQueueAsBarrier(DispatchQueue)

//Predicates that the evaluated context is not the associated dispatch queue.
case notOnQueue(DispatchQueue)

// onQueueAsBarrier
let dataQueue = DispatchQueue(label: "data", attributes: .concurrent)
let wirte = DispatchWorkItem(flags: .barrier) {
     dispatchPrecondition(condition: .onQueueAsBarrier(dataQueue))
    // write data
}
dataQueue.async(execute: wirte)

let queue = DispatchQueue.global()
let mainQueue = DispatchQueue.main
// .notOnQueue
mainQueue.async {
    dispatchPrecondition(condition: .notOnQueue(mainQueue))
    // This code won't execute
}
// onQueue
queue.async {
    dispatchPrecondition(condition: .onQueue(queue))
    // This code will execute
}

}

參考文檔
https://developer.apple.com/videos/play/wwdc2016/720/
http://gold.xitu.io/post/57f6677e128fe100544dc3cb
https://github.com/apple/swift-evolution/blob/master/proposals/0088-libdispatch-for-swift3.md

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末祷愉,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子赦颇,更是在濱河造成了極大的恐慌二鳄,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件媒怯,死亡現(xiàn)場離奇詭異订讼,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)沪摄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評論 3 385
  • 文/潘曉璐 我一進(jìn)店門躯嫉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纱烘,“玉大人,你說我怎么就攤上這事祈餐±奚叮” “怎么了?”我有些...
    開封第一講書人閱讀 157,435評論 0 348
  • 文/不壞的土叔 我叫張陵帆阳,是天一觀的道長哺壶。 經(jīng)常有香客問我,道長蜒谤,這世上最難降的妖魔是什么山宾? 我笑而不...
    開封第一講書人閱讀 56,509評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮鳍徽,結(jié)果婚禮上资锰,老公的妹妹穿的比我還像新娘。我一直安慰自己阶祭,他們只是感情好绷杜,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,611評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著濒募,像睡著了一般鞭盟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上瑰剃,一...
    開封第一講書人閱讀 49,837評論 1 290
  • 那天齿诉,我揣著相機(jī)與錄音,去河邊找鬼晌姚。 笑死粤剧,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的舀凛。 我是一名探鬼主播俊扳,決...
    沈念sama閱讀 38,987評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼猛遍!你這毒婦竟也來了馋记?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,730評論 0 267
  • 序言:老撾萬榮一對情侶失蹤懊烤,失蹤者是張志新(化名)和其女友劉穎梯醒,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體腌紧,經(jīng)...
    沈念sama閱讀 44,194評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡茸习,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,525評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了壁肋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片号胚。...
    茶點(diǎn)故事閱讀 38,664評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡籽慢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤狐肢,帶...
    沈念sama閱讀 34,334評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站届惋,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏菠赚。R本人自食惡果不足惜脑豹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,944評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望衡查。 院中可真熱鬧瘩欺,春花似錦、人聲如沸拌牲。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽们拙。三九已至,卻和暖如春阁吝,著一層夾襖步出監(jiān)牢的瞬間砚婆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評論 1 266
  • 我被黑心中介騙來泰國打工突勇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留装盯,地道東北人。 一個月前我還...
    沈念sama閱讀 46,389評論 2 360
  • 正文 我出身青樓甲馋,卻偏偏與公主長得像埂奈,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子定躏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,554評論 2 349

推薦閱讀更多精彩內(nèi)容