iOS GCD學(xué)習(xí)總結(jié)(二)

1.GCD 線程間的通信

在 iOS 開(kāi)發(fā)過(guò)程中,當(dāng)我們有時(shí)候在其他線程完成了耗時(shí)操作時(shí),需要回到主線程,那么就用到了線程之間的通訊。

    func communication(){
        DispatchQueue.global().async {          //異步添加任務(wù) 例如:文件上傳、下載、接口請(qǐng)求
            sleep(2)                            //模擬耗時(shí)操作
            DispatchQueue.main.async {
                self.tableView.reloadData()     //更新ui
            }
        }
    }

如果想了解為啥一定要在主線程更新ui的話,https://juejin.im/post/5c406d97e51d4552475fe178,https://www.cnblogs.com/8335IT/p/10373723.html

1.GCD 其他方法

柵欄方法:dispatch_barrier_async

一個(gè)dispatch barrier 允許在一個(gè)并發(fā)隊(duì)列中創(chuàng)建一個(gè)同步點(diǎn)。當(dāng)在并發(fā)隊(duì)列中遇到一個(gè)barrier, 他會(huì)延遲執(zhí)行barrier的block,等待所有在barrier之前提交的blocks執(zhí)行結(jié)束。 這時(shí),barrier block自己開(kāi)始執(zhí)行。 之后, 隊(duì)列繼續(xù)正常的執(zhí)行操作。這里指定的并發(fā)隊(duì)列應(yīng)該是自己通過(guò)dispatch_queue_create函數(shù)創(chuàng)建的。如果你傳的是一個(gè)串行隊(duì)列或者全局并發(fā)隊(duì)列,這個(gè)函數(shù)等同于dispatch_async函數(shù)。
所有在barrier block之后提交的blocks會(huì)等到barrier block結(jié)束之后才執(zhí)行

    /**
    *  柵欄方法 dispatch_barrier_async 
    *  基本操作
    */
    func barrier(){
        let queue = DispatchQueue.init(label: "barrier", attributes: .concurrent)
        queue.async {//追加任務(wù)1
            sleep(2)
            print("1---\(Thread.current)")
        }
        queue.async {//追加任務(wù)2
            sleep(2)
            print("2---\(Thread.current)")
        }
        queue.async(flags: .barrier) {//追加任務(wù)barrier
            sleep(1)
            print("barrier---\(Thread.current)")
        }
        queue.async {//追加任務(wù)3
            print("3---\(Thread.current)")
        }
    }
輸出:
2---<NSThread: 0x282250ac0>{number = 5, name = (null)}
1---<NSThread: 0x282276bc0>{number = 6, name = (null)}
barrier---<NSThread: 0x282276bc0>{number = 6, name = (null)}
3---<NSThread: 0x282276bc0>{number = 6, name = (null)}

從以上可以看出在執(zhí)行完?yáng)艡谇懊娴牟僮髦螅艌?zhí)行柵欄操作,最后再執(zhí)行柵欄后邊的操作

那如果dispatch_barrier_sync用同步會(huì)有什么效果了呢?

    /**
    * 柵欄方法 dispatch_barrier_sync
    */
    func syncbarrier(){
        let queue = DispatchQueue.init(label: "syncbarrier", attributes: .concurrent)
        queue.async {
            sleep(2)
            print("1---\(Thread.current)")
        }
        queue.sync(flags: .barrier) {
            sleep(1)
            print("barrier---\(Thread.current)")
        }
        
        print("我在主線程上---\(Thread.current)")
        
        queue.async {
            print("3---\(Thread.current)")
        }
    }
輸出:
1---<NSThread: 0x280860b80>{number = 5, name = (null)}
barrier---<NSThread: 0x280802e40>{number = 1, name = main}
我在主線程上---<NSThread: 0x280802e40>{number = 1, name = main}
3---<NSThread: 0x280860b80>{number = 5, name = (null)}

以上輸出可以看出,dispatch_barrier_sync如果傳入自己創(chuàng)建的并行隊(duì)列時(shí),阻塞當(dāng)前隊(duì)列的同時(shí)也會(huì)阻塞當(dāng)前線程,而dispatch_barrier_async不會(huì)阻塞當(dāng)前線程。更多dispatch_barrier_sync用法請(qǐng)轉(zhuǎn):dispatch_barrier_sync實(shí)現(xiàn)多讀單寫(xiě)

延時(shí)執(zhí)行方法:dispatch_after

dispatch_after 方法并不是在指定時(shí)間之后才開(kāi)始執(zhí)行處理,而是在指定時(shí)間之后將任務(wù)追加到主隊(duì)列中。嚴(yán)格來(lái)說(shuō),這個(gè)時(shí)間并不是絕對(duì)準(zhǔn)確的,但想要大致延遲執(zhí)行任務(wù),dispatch_after 方法是很有效的

    /**
    * 延時(shí)執(zhí)行方法 dispatch_after
    */
    func after(){
        print("1---\(Thread.current)")
        print("begin")
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            print("after---\(Thread.current)")//延遲2秒輸出
        }
        print("end")
    }
輸出:
1---<NSThread: 0x174078780>{number = 1, name = main}
begin
end
after---<NSThread: 0x174078780>{number = 1, name = main}
一次性代碼(只執(zhí)行一次):dispatch_once

我們?cè)趧?chuàng)建單例、或者有整個(gè)程序運(yùn)行過(guò)程中只執(zhí)行一次的代碼時(shí),我們就用到了 GCD 的 dispatch_once 方法。使用 dispatch_once 方法能保證某段代碼在程序運(yùn)行過(guò)程中只被執(zhí)行 1 次,并且即使在多線程的環(huán)境下,dispatch_once 也可以保證線程安全。因 swift4.0已廢棄dispatch_once,所以需要手動(dòng)實(shí)現(xiàn)

//MARK:擴(kuò)展實(shí)現(xiàn)一次性代碼
public extension DispatchQueue{
     private static var _onceTracker = [String]()
    
    class func once(token:String, block:()->()){
        objc_sync_enter(self)
        defer {
            objc_sync_exit(self)
        }
        guard !_onceTracker.contains(token) else {return}
        _onceTracker.append(token)
        block()
    }
}

  //調(diào)用
  DispatchQueue.once(token: "uniquely_identifies") {
       print("Do This Once!")
  }

defer:延遲調(diào)用,調(diào)用時(shí)機(jī)是在離開(kāi)作用域之后,其他語(yǔ)句之前 。
objc_sync_enter、objc_sync_exit:保證線程安全

快速迭代方法:dispatch_apply

該函數(shù)按指定的次數(shù)將指定的Block追加到指定的Dispatch Queue中,并等待全部處理執(zhí)行結(jié)束,好處是可以重復(fù)執(zhí)行某項(xiàng)操作并復(fù)用我們的Block了,swift 已廢棄該方法。

    /**
    * 快速迭代方法:dispatch_apply
    */
    func apply(){
        //如果把隊(duì)列改成串行就是按順序執(zhí)行
        let queue = DispatchQueue.init(label: "apply", attributes: .concurrent)
        queue.async {
            DispatchQueue.concurrentPerform(iterations: 5) { (index) in
                print("重復(fù)操作:\(index)---\(Thread.current)")
            }
            print("end")
        }
    }
    //輸出:
    重復(fù)操作:1---<NSThread: 0x17007b280>{number = 4, name = (null)}
    重復(fù)操作:2---<NSThread: 0x17007b280>{number = 4, name = (null)}
    重復(fù)操作:3---<NSThread: 0x17007b280>{number = 4, name = (null)}
    重復(fù)操作:4---<NSThread: 0x17007b280>{number = 4, name = (null)}
    重復(fù)操作:0---<NSThread: 0x17407fc40>{number = 3, name = (null)}
    end
    //例:
    func apply(){
        let dictArray:[[String:Any]] = []
        let queue = DispatchQueue.init(label: "apply", attributes: .concurrent)
        queue.async {
            DispatchQueue.concurrentPerform(iterations: dictArray.count) { (index) in
                //字典轉(zhuǎn)模型
            }
            DispatchQueue.main.async {
                //主線程更新
            }
        }
    }
隊(duì)列組:dispatch_group

有時(shí)候我們會(huì)有個(gè)這樣的需求,要等到兩個(gè)或更多的耗時(shí)任務(wù)都完成后再做其他操作,這時(shí)候我們可以想到隊(duì)列組

dispatch_group_notify:

    /**
    * dispatch_group_notify
    */
    func group(){
        let group = DispatchGroup.init()
        let queue = DispatchQueue.init(label: "group", attributes: .concurrent)
        queue.async(group: group) {
            sleep(2)//耗時(shí)任務(wù)
            print("1---\(Thread.current)")
        }
        queue.async(group: group) {
            sleep(5)//耗時(shí)任務(wù)
            print("2---\(Thread.current)")
        }
        group.notify(queue: DispatchQueue.main) {
            print("main---\(Thread.current)")
        }
    }
    //輸出:
    1---<NSThread: 0x282cbf7c0>{number = 1, name = main}
    2---<NSThread: 0x282cbf7c0>{number = 1, name = main}
    main---<NSThread: 0x282cbf7c0>{number = 1, name = main}

dispatch_group_wait:

    /**
    * dispatch_group_wait
    */
    func groupWait(){
        let group = DispatchGroup.init()
        let queue = DispatchQueue.init(label: "group", attributes: .concurrent)
        queue.async(group: group) {
            sleep(2)//耗時(shí)任務(wù)
            print("1---\(Thread.current)")
        }
        queue.async(group: group) {
            sleep(5)//耗時(shí)任務(wù)
            print("2---\(Thread.current)")
        }
        // 等待上面的任務(wù)全部完成后,會(huì)往下繼續(xù)執(zhí)行(會(huì)阻塞當(dāng)前線程)
        group.wait()
        print("end")
    }
輸出:
1---<NSThread: 0x283aa9940>{number = 6, name = (null)}
2---<NSThread: 0x283abc200>{number = 5, name = (null)}
end

dispatch_group_enter、dispatch_group_leave:

    /**
    * dispatch_group_enter、dispatch_group_leave
    */
    func groupEnterAndLeave(){
        let group = DispatchGroup.init()
        let queue = DispatchQueue.init(label: "groupEnterAndLeave", attributes: .concurrent)
        group.enter()
        queue.async(group: group) {
            sleep(2)//耗時(shí)任務(wù)
            print("1---\(Thread.current)")
            group.leave()
        }
        
        group.enter()
        queue.async(group: group) {
            sleep(5)//耗時(shí)任務(wù)
            print("2---\(Thread.current)")
            group.leave()
        }
        
        group.notify(queue: DispatchQueue.main) {
            print("end")
        }
    }
輸出:
1---<NSThread: 0x281efecc0>{number = 5, name = (null)}
2---<NSThread: 0x281ef77c0>{number = 6, name = (null)}
end

簡(jiǎn)單說(shuō)一下原理,group是基于信號(hào)量現(xiàn)實(shí),group的本質(zhì)是一個(gè)初始值為L(zhǎng)ONG_MAX的信號(hào)量,通過(guò)信號(hào)量來(lái)實(shí)現(xiàn)各個(gè)任務(wù)的管理

iOS GCD學(xué)習(xí)總結(jié)(一)
iOS 線程同步方案學(xué)習(xí)總結(jié)
信號(hào)量semaphore學(xué)習(xí)總結(jié)
iOS dispatch_barrier_sync實(shí)現(xiàn)多讀單寫(xiě)
NSOperation和NSOperationQueue學(xué)習(xí)總結(jié)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容