Swift GCD之解決多個網(wǎng)絡(luò)請求的尷尬

  • 項目開發(fā)過程中, 經(jīng)常遇到單個頁面需要發(fā)起多個網(wǎng)絡(luò)請求, 而且還需要控制執(zhí)行順序或者所有請求結(jié)束后統(tǒng)一處理數(shù)據(jù)的情況. 最明顯的解決方案就是嵌套,但是如果請求多了,代碼確實有點惡心

DispatchQueue

  • 串行隊列的創(chuàng)建
let queue = DispatchQueue(label: "myQueue")
  • 并行隊列的創(chuàng)建, 參數(shù)說明
    • label: 隨意命名,隊列的標(biāo)識
    • qos(服務(wù)質(zhì)量): DispatchQoS.default DispatchQoS.background(后臺執(zhí)行) DispatchQoS.unspecified(不指定) DispatchQoS.userInitiated(用戶發(fā)起) 等
    • attributes: DispatchQueue.Attributes.concurrent(并行隊列) 不指定的情況是串行隊列
    • autoreleaseFrequency(自動釋放的頻度): inherit(繼承) workItem(工作組) never(從不)
let queue = DispatchQueue(label: "myQueue", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit, target: nil)
  • 簡單使用
let queue = DispatchQueue(label: "myQueue", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit, target: nil)

queue.async {
    sleep(1)
    print("in queue 111")
}
queue.async {
    sleep(1)
    print("in queue 222")
}

print("finish")
image

DispatchGroup(進入正題)

線程組有兩種模式, 阻塞式(DispatchGroup-wait) 和 非阻塞式(DispatchGroup-notify)

wait

workingGroup.enter() 和 workingGroup.leave() 要成對出現(xiàn), 只有l(wèi)eave()之后才會開始新的enter()
隊列中的請求任務(wù)是否順序執(zhí)行, 取決于自己創(chuàng)建的隊列類型

// DispatchGroup-wait(阻塞)
let workingGroup = DispatchGroup()
let workingQueue = DispatchQueue(label: "request_queue") // 這個是串行的隊列, queue里面的任務(wù)會順序執(zhí)行
//let workingQueue = DispatchQueue(label: "request_queue1", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit, target: nil) // 這個是并行隊列, queue里面的任務(wù)會同時執(zhí)行

workingGroup.enter() // 開始
workingQueue.async {
    Thread.sleep(forTimeInterval: 2)
    print("接口 A 數(shù)據(jù)表請求完成")
    workingGroup.leave() // 結(jié)束
}

workingGroup.enter() // 開始
workingQueue.async {
    Thread.sleep(forTimeInterval: 1)
    print("接口 B 數(shù)據(jù)表請求完成")
    workingGroup.leave() // 結(jié)束
}
print("========= 我是最開始執(zhí)行的 =========")

workingGroup.wait() // 阻塞, 直到Group中的任務(wù)都結(jié)束

print("接口 A 和接口 B 的數(shù)據(jù)都已經(jīng)請求完畢, 開始合并兩個接口的數(shù)據(jù)")
print("========= 完美結(jié)束完美結(jié)束 =========")
image

notify

任務(wù)結(jié)束后, 通過通知回調(diào)的方式繼續(xù)執(zhí)行, 同時不會阻塞線程

// DispatchGroup-notify(不阻塞)
let workingGroup1 = DispatchGroup()
//let workingQueue1 = DispatchQueue(label: "request_queue1", qos: DispatchQoS.default, attributes: DispatchQueue.Attributes.concurrent, autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit, target: nil) // 創(chuàng)建并行隊列
let workingQueue1 = DispatchQueue(label: "request_queue1") // 創(chuàng)建的默認(rèn)隊列是串行隊列

workingGroup1.enter()
workingQueue1.async {
    Thread.sleep(forTimeInterval: 2)
    print("接口 C 數(shù)據(jù)表請求完成")
    workingGroup1.leave()
}

workingGroup1.enter()
workingQueue1.async {
    Thread.sleep(forTimeInterval: 1)
    print("接口 D 數(shù)據(jù)表請求完成")
    workingGroup1.leave()
}

print("↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 我是最開始執(zhí)行的 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓")
workingGroup.notify(queue: workingQueue1) {
    print("接口 C 和接口 D 的數(shù)據(jù)都已經(jīng)請求完畢, 開始合并兩個接口的數(shù)據(jù)")
}

print("驗證不阻塞 O(∩_∩)O哈哈~")

image

結(jié)束語

媽媽再也不用擔(dān)心我了

通過實際操作, 同時發(fā)起多個網(wǎng)絡(luò)請求, 發(fā)現(xiàn)以上的兩種方式, 只是控制了請求的順序, 并沒有控制返回數(shù)據(jù)的順序, 然后心態(tài)崩了, 只是崩了一小會兒, 繼續(xù)往下, 問題解決

swift中的信號量使用

// 創(chuàng)建初始值為0的信號量,這時代表是紅燈
let sema = DispatchSemaphore(value: 0)

// 讓信號量 -1,比如默認(rèn)值時0, wait()以后就變成了 -1了,因此會等待
sema.wait()

// 讓信號量 +1, 當(dāng)>0時就代表綠燈可以走了
sema.signal()

let workingGroup = DispatchGroup()
let workingQueue = DispatchQueue(label: "request_queue")

workingGroup.enter() // 開始
workingQueue.async {
    let sema = DispatchSemaphore(value: 0)
    let params = ["id": "458"]
    self.req1(params, sema: sema)
    sema.wait() // 等待任務(wù)結(jié)束, 否則一直阻塞
    workingGroup.leave() // 結(jié)束
}
workingGroup.enter() // 開始
workingQueue.async {
    let sema = DispatchSemaphore(value: 0)
    self.req2(self.productId, sema: sema)
    sema.wait() // 等待任務(wù)結(jié)束, 否則一直阻塞
    workingGroup.leave() // 結(jié)束
}

workingGroup.notify(queue: DispatchQueue.main) {
    // 全部調(diào)用完成后回到主線程,更新UI
}

private func req1(_ params: [String: Any], sema: DispatchSemaphore) {
    LBProductNetManager.req_addOrApplyNow(params: params, success: { (result) in
        // 信號量+1
        sema.signal()
    }) { (error) in
        // 失敗的時候也要+1, 否則會永遠阻塞了
        sema.signal()
    }
}

private func req2(_ productId: Int, sema: DispatchSemaphore) {
    LBProductNetManager.req_getHealthNotice(213, success: { (result) in
        // 信號量+1
        sema.signal()
    }) { (error) in
        // 失敗的時候也要+1, 否則會永遠阻塞了
        sema.signal()
    }
}

摘自 Chaos_G 本文僅作為學(xué)習(xí)使用 如有侵權(quán) 麻煩聯(lián)系我 立即刪除

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

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