GCD在Swift中的使用

一個(gè)常見(jiàn)的場(chǎng)景就是在一個(gè)全局隊(duì)列進(jìn)行一些操作后切換到主線程配置UI。現(xiàn)在是這么寫(xiě):

DispatchQueue.global().async {
    // code
    DispatchQueue.main.async {
        // 主線程中
    }
}

概念:

串行 VS 并發(fā)

串行與并發(fā)用來(lái)表述隊(duì)列里面的任務(wù)執(zhí)行的順序啄刹。 串行(serial) 在同一時(shí)間點(diǎn)總是單獨(dú)執(zhí)行一個(gè)任務(wù)乙墙,并發(fā)(concurrent)則可以同時(shí)執(zhí)行多個(gè)任務(wù)颠锉。

任務(wù)

任務(wù)可以看成是一段未被執(zhí)行的代碼塊, 一個(gè)方法可以是一個(gè)一個(gè)任務(wù), 一寫(xiě)代碼的集合可以看做是一個(gè)任務(wù), 在GCD中, 隊(duì)列里面的任務(wù)就是未被執(zhí)行的一塊閉包

同步 VS 異步

同步和異步表述的是函數(shù)何時(shí)將控制權(quán)返回給調(diào)用者拼卵,以及在返回時(shí)任務(wù)的完成情況。
同步(任務(wù)一個(gè)一個(gè)執(zhí)行)函數(shù)只有在任務(wù)完成后才會(huì)返回虏杰。
異步(任務(wù)可以并發(fā)執(zhí)行)函數(shù)會(huì)立即返回讥蟆,不會(huì)等待任務(wù)完成。因此異步函數(shù)不會(huì)阻塞當(dāng)前線程纺阔。

主隊(duì)列

系統(tǒng)提供了一種特殊的順序隊(duì)列 main queue瘸彤。和其他的順序隊(duì)列一樣,在這個(gè)隊(duì)列里的任務(wù)同一時(shí)刻只有一個(gè)在執(zhí)行笛钝。然而质况,這個(gè)隊(duì)列保證了所有任務(wù)會(huì)在主線程中執(zhí)行,主線程是唯一一個(gè)允許更新UI的線程玻靡。這個(gè)隊(duì)列用來(lái)向 UIView 對(duì)象發(fā)消息或發(fā)通知结榄。

隊(duì)列優(yōu)先級(jí)

原先的GCD只有四個(gè)優(yōu)先級(jí),high囤捻,default潭陪,low,background
然而現(xiàn)在的GCD有六個(gè)優(yōu)先級(jí)最蕾,background,utility老厌,default瘟则,userInitiated,userInteractive枝秤,unspecified
這些優(yōu)先級(jí)有結(jié)構(gòu)體DispatchQoS來(lái)管理

串行隊(duì)列

//創(chuàng)建的隊(duì)列默認(rèn)是串行的,  隊(duì)列里的任務(wù)是以此按照添加的順序來(lái)執(zhí)行的(FIFO)
//第一個(gè)for循環(huán)結(jié)束之后才會(huì)執(zhí)行下一個(gè)for循環(huán)
func serialQueues() {
        let queue = DispatchQueue(label: "com.jason")
        //創(chuàng)建一個(gè)含有優(yōu)先級(jí)的串行隊(duì)列
         //let anotherQueue = DispatchQueue(label:"com.appcoda.anotherQueue", qos:.utility)

        queue.async {
            for i in 1..<10 {
                print("??" + String(i))
            }
        }
        
        queue.async {
            for i in 1..<10 {
                print("??" + String(i))
            }

        }
    }

并行隊(duì)列

    func concurrentQueues() {
        
        //并行隊(duì)列, 隊(duì)列里面的任務(wù)并發(fā)執(zhí)行
        /**
            label: 隊(duì)列的唯一標(biāo)識(shí)符
            qos: 優(yōu)先級(jí)
            attributes: 隊(duì)列類(lèi)型
          */
        let anotherQueue = DispatchQueue(label:"com.appcoda.anotherQueue", qos:.utility, attributes:.concurrent)
        anotherQueue.async {
            for i in 1..<10 {
                print("??" + String(i))
            }
        }
        anotherQueue.async {
            for i in 1..<10 {
                print("??" + String(i))
            }
        }
    }
    

初始化不活躍的串行隊(duì)列

    
    var inactiveQueue: DispatchQueue!
    func concurrentQueues() {        
        //串行隊(duì)列, 初始不活躍, 需要時(shí)才執(zhí)行
        let anotherQueue = DispatchQueue(label:"com.appcoda.anotherQueue", qos:.utility, attributes:.initiallyInactive)
        inactiveQueue = anotherQueue
        anotherQueue.async {
            for i in 1..<10 {
                print("??" + String(i))
            }
        }
        anotherQueue.async {
            for i in 1..<10 {
                print("??" + String(i))
            }
        }
   }

調(diào)用

         concurrentQueues()
         if let queue = inactiveQueue {
            queue.activate()
         }

初始化不活躍的并行隊(duì)列

        //并行隊(duì)列, 初始不活躍
 let anotherQueue = DispatchQueue(label:"com.appcoda.anotherQueue", qos:.utility, attributes:[.initiallyInactive, .concurrent])

延遲執(zhí)行

    func queueWithDelay() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 5) { 
            print("延遲5秒執(zhí)行")
        }
    }

DispatchWorkItem

DispatchWorkItem是一個(gè)代碼塊醋拧,它可以被分到任何的隊(duì)列,包含的代碼可以在后臺(tái)或主線程中被執(zhí)行淀弹,簡(jiǎn)單來(lái)說(shuō):它被用于替換我們前面寫(xiě)的閉包

    func useWorkItem() {
        var value = 10
        //創(chuàng)建一個(gè)workItem
        let workItem = DispatchWorkItem {
            value += 5
        }
        //激活workItem
        workItem.perform()
        //獲取全局一個(gè)隊(duì)列
        let queue = DispatchQueue.global()
        //在隊(duì)列里面執(zhí)行workItem
        queue.async(execute: workItem)
        //workItem被執(zhí)行完成后收到的通知
        workItem.notify(queue: DispatchQueue.main) {
            print(value)
        }   
    }

DispatchGroup(任務(wù)組)

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

let group = DispatchGroup()

let queueBook = DispatchQueue(label: "book")
queueBook.async(group: group) {
    // 下載圖書(shū)
}
let queueVideo = DispatchQueue(label: "video")
queueVideo.async(group: group) {
    // 下載視頻
}

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

DispatchGroup會(huì)在組里的操作都完成后執(zhí)行notify薇溃。


監(jiān)聽(tīng) group 中任務(wù)的完成狀態(tài)菌赖,當(dāng)所有的任務(wù)都執(zhí)行完成后,追加任務(wù)到 group 中沐序,并執(zhí)行任務(wù)琉用。

func groupNotify() {
        let group = DispatchGroup();
        let mainQueue = DispatchQueue.main;
        let queue = DispatchQueue.global();
        let item1 = DispatchWorkItem.init {
            for _ in 0..<2 {
                Thread.sleep(forTimeInterval: 2)
                print("1---\(Thread.current)")
            }
        }
        let item2 = DispatchWorkItem.init {
            for _ in 0..<2 {
                Thread.sleep(forTimeInterval: 2)
                print("2---\(Thread.current)")
            }
        }
        
        queue.async(group: group, execute: item1)
        queue.async(group: group, execute: item2)
        group.notify(queue: mainQueue) {
            for _ in 0..<2 {
                Thread.sleep(forTimeInterval: 2)
                print("3---\(Thread.current)")
            }
        }
    }
   

dispatch_group_enter堕绩、dispatch_group_leave
dispatch_group_enter 標(biāo)志著一個(gè)任務(wù)追加到 group,執(zhí)行一次邑时,相當(dāng)于 group 中未執(zhí)行完畢任務(wù)數(shù)+1
dispatch_group_leave 標(biāo)志著一個(gè)任務(wù)離開(kāi)了 group奴紧,執(zhí)行一次,相當(dāng)于 group 中未執(zhí)行完畢任務(wù)數(shù)-1晶丘。
當(dāng) group 中未執(zhí)行完畢任務(wù)數(shù)為0的時(shí)候黍氮,才會(huì)使dispatch_group_wait解除阻塞,以及執(zhí)行追加到dispatch_group_notify中的任務(wù)浅浮。
這里的dispatch_group_enter沫浆、dispatch_group_leave組合,其實(shí)等同于dispatch_group_async脑题。

    func groupEnterAndLeave() {
        let group = DispatchGroup();
        let mainQueue = DispatchQueue.main;
        let queue = DispatchQueue.global();
        
        group.enter()
        queue.async {
            for _ in 0..<2 {
                Thread.sleep(forTimeInterval: 2)
                print("1---\(Thread.current)")
            }
            group.leave()
        }
        
        group.enter()
        queue.async {
            for _ in 0..<2 {
                Thread.sleep(forTimeInterval: 2)
                print("2---\(Thread.current)")
            }
            group.leave()
        }
        
        group.notify(queue: mainQueue) {
            for _ in 0..<2 {
                Thread.sleep(forTimeInterval: 2)
                print("3---\(Thread.current)")
            }
        }
    }
 

單例

//final關(guān)鍵字的作用是這個(gè)類(lèi)或方法不希望被繼承和重寫(xiě)
final class Single: NSObject {
    static let shared = Single()
    //這里的所有單例init方法一定要定義成private的件缸,不然外部依然可以使用init方法初始化變量。
    private override init() {}
}
//靜態(tài)變量進(jìn)行創(chuàng)建
final class Singleton {
    static private let staticInstance: Singleton = Singleton()
    static func sharedInstance() -> Singleton {
        return staticInstance
    }
    private init() {}
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末叔遂,一起剝皮案震驚了整個(gè)濱河市他炊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌已艰,老刑警劉巖痊末,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異哩掺,居然都是意外死亡凿叠,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)嚼吞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)盒件,“玉大人,你說(shuō)我怎么就攤上這事舱禽〕吹螅” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵誊稚,是天一觀的道長(zhǎng)翔始。 經(jīng)常有香客問(wèn)我,道長(zhǎng)里伯,這世上最難降的妖魔是什么城瞎? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮疾瓮,結(jié)果婚禮上脖镀,老公的妹妹穿的比我還像新娘。我一直安慰自己狼电,他們只是感情好认然,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布补憾。 她就那樣靜靜地躺著,像睡著了一般卷员。 火紅的嫁衣襯著肌膚如雪盈匾。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,562評(píng)論 1 305
  • 那天毕骡,我揣著相機(jī)與錄音削饵,去河邊找鬼。 笑死未巫,一個(gè)胖子當(dāng)著我的面吹牛窿撬,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播叙凡,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼劈伴,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了握爷?” 一聲冷哼從身側(cè)響起跛璧,我...
    開(kāi)封第一講書(shū)人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎新啼,沒(méi)想到半個(gè)月后追城,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡燥撞,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年座柱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片物舒。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡色洞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出冠胯,到底是詐尸還是另有隱情锋玲,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布涵叮,位于F島的核電站,受9級(jí)特大地震影響伞插,放射性物質(zhì)發(fā)生泄漏割粮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一媚污、第九天 我趴在偏房一處隱蔽的房頂上張望舀瓢。 院中可真熱鬧,春花似錦耗美、人聲如沸京髓。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)堰怨。三九已至芥玉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間备图,已是汗流浹背灿巧。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留揽涮,地道東北人抠藕。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蒋困,于是被迫代替她去往敵國(guó)和親盾似。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

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