天天看點

iOS Swift 中 DispatchGroup 分組管理異步任務使用

一、DispatchGroup三種用法:

1. notify(依賴任務)
let group = DispatchGroup()
        myQueue?.async(group: group, qos: .default, flags: [], execute: { 
            for _ in 0...10 {
               print("耗時任務一")
            }
        })
        myQueue?.async(group: group, qos: .default, flags: [], execute: {
            for _ in 0...10 {
                print("耗時任務二")
            }
        })
        //執行完上面的兩個耗時操作, 回到myQueue隊列中執行下一步的任務
        group.notify(queue: myQueue!) {
            print("回到該隊列中執行")
        }
           
2. wait(任務等待)
let group = DispatchGroup()
        myQueue?.async(group: group, qos: .default, flags: [], execute: {
            for _ in 0...10 {

                print("耗時任務一")
            }
        })
        myQueue?.async(group: group, qos: .default, flags: [], execute: {
            for _ in 0...10 {

                print("耗時任務二")
                sleep(UInt32(3))
            }
        })
         //等待上面任務執行,會阻塞目前線程,逾時就執行下面的,上面的繼續執行。可以無限等待 .distantFuture
        let result = group.wait(timeout: .now() + 2.0)
        switch result {
        case .success:
            print("不逾時, 上面的兩個任務都執行完")
        case .timedOut:
            print("逾時了, 上面的任務還沒執行完執行這了")
        }

        print("接下來的操作")
           
3. enter leave 手動管理group計數,enter和leave必須配對
let group = DispatchGroup()
        group.enter()//把該任務添加到組隊列中執行
        myQueue?.async(group: group, qos: .default, flags: [], execute: {
            for _ in 0...10 {

                print("耗時任務一")
                group.leave()//執行完之後從組隊列中移除
            }
        })
         group.enter()//把該任務添加到組隊列中執行
        myQueue?.async(group: group, qos: .default, flags: [], execute: {
            for _ in 0...10 {

                print("耗時任務二")
                group.leave()//執行完之後從組隊列中移除
            }
        })

        //當上面所有的任務執行完之後通知
        group.notify(queue: .main) { 
            print("所有的任務執行完了")
        }
           

二、項目中的實際用例

這次遇到的是一個循環網絡請求的功能(怎麼老是遇上這種蛋疼的API),要求本地存儲的數組裡循環取出存儲對象,并使用存儲對象的屬性做參數,POST請求。然後将每次請求下來的資料進行累加計算,最後指派。上代碼:

func sumTheassets(compHandler:@escaping (_ sum:Float)->()) {
        var asset:Float = 0
        let group = DispatchGroup() //建立group
        for object in objects {  //for循環便利本地存儲的數組資料
            group.enter() // 将以下任務添加進group
            let cellViewmodel = MyassetsCellViewModel() // 建立VM對象,并調用網絡請求函數
            cellViewmodel.getThepriceFromnew(symbol: object.symbol, compHandler: { (price, ratio) in
                let decimals = Float(object.decimals) // 擷取數量,轉為Float型
                let num = price * decimals! //計算總價格  單價 * 數量
                asset += num //将計算結果累加
                group.leave() //本次任務完成(即本次for循環任務完成),将任務從group中移除
            })
        }
        group.notify(queue: .main) {  // group中的所有任務完成後再主線程中調用回調函數,将結果傳出去
            compHandler(asset)  //在回調裡将累加結果傳出去
        }
    }
           

以上,祝大家在開發中都不遇到奇葩API接口或需求 (美好的理想啊)