關(guān)于多個(gè)網(wǎng)絡(luò)請(qǐng)求同步的一些總結(jié)

等待多個(gè)并發(fā)請(qǐng)求同步回調(diào)

例如同時(shí)發(fā)起網(wǎng)絡(luò)請(qǐng)求A,網(wǎng)絡(luò)請(qǐng)求B犯助,網(wǎng)絡(luò)請(qǐng)求C蜂桶,需等待A,B也切,C都返回了才進(jìn)行回調(diào)扑媚。曾經(jīng)是利用 block 嵌套腰湾,就是A回調(diào)嵌B,B回調(diào)嵌C疆股,十分膚淺的做法╮(╯▽╰)╭
這里介紹 GCD 中的兩種方法费坊,第一種是利用 DispatchGroupenterleave,第二種是利用 DispatchSemaphore 信號(hào)量旬痹。
以下代碼是基于 swift 3.0.2附井。
首先先創(chuàng)建一個(gè)模擬請(qǐng)求。

    // 假裝是網(wǎng)絡(luò)請(qǐng)求
    func networkRequest(sleepTime: Int, closure: @escaping ()->Void) -> Void {
        DispatchQueue.global().async { 
            Thread.sleep(forTimeInterval: TimeInterval(sleepTime))
            // 假裝是成功回調(diào)
            closure()
        }
    }

第一種方法利用 enter&leave两残。需要注意的是 enter&leave 必須成對(duì)出現(xiàn)永毅,enter 少了會(huì)崩潰,leave 少了則永遠(yuǎn)不會(huì)執(zhí)行 notify 函數(shù)人弓。
這種方法的原理就是:

  1. 請(qǐng)求前 enter沼死。
  2. 請(qǐng)求完成后 leave
    // 利用 enter/leave 來(lái)控制
    func gcd_group_enter_leave() {
        let group = DispatchGroup.init()
        let queue = DispatchQueue.global()
        
        queue.async(group: group) {
            group.enter()
            print("1 start")
            self.networkRequest(sleepTime:1, closure: {
                print("1 end")
                group.leave()
            })
        }
        
        queue.async(group: group) {
            group.enter()
            print("2 start")
            self.networkRequest(sleepTime:2, closure: {
                print("2 end")
                group.leave()
            })
        }
        
        queue.async(group: group) {
            group.enter()
            print("3 start")
            self.networkRequest(sleepTime:2, closure: {
                print("3 end")
                group.leave()
            })
        }
        
        queue.async(group: group) {
            group.enter()
            print("4 start")
            self.networkRequest(sleepTime:2, closure: {
                print("4 end")
                group.leave()
            })
        }
        
        group.notify(queue: queue) { // 所有組完成后回調(diào)
            print("all done")
        }
    }

第二種方法是利用信號(hào)量的 wait&signal崔赌,簡(jiǎn)單來(lái)說(shuō)就是:signal 就是釋放信號(hào)即信號(hào)量 +1意蛀,wait 就是等待信號(hào)即信號(hào)量-1。wait&signal也是必須成對(duì)出現(xiàn)健芭。
這種方法的原理就是:

  1. 創(chuàng)建0信號(hào)量县钥。
  2. 請(qǐng)求完成釋放信號(hào),使得信號(hào)量+1慈迈。
  3. notify 的回調(diào)操作前加入 wait 操作(多少請(qǐng)求就加多少 wait若贮,這要做為了得到足夠的信號(hào)量才能執(zhí)行 wait 下面的代碼)。
    // 利用 semaphore 來(lái)控制
    func gcd_semaphore_wait_signal() {
        let semaphore = DispatchSemaphore.init(value: 0)
        let group = DispatchGroup.init()
        let queue = DispatchQueue.global()
        
        queue.async(group: group) {
            self.networkRequest(sleepTime:1, closure: {
                print("1")
                semaphore.signal()
            })
        }
        
        queue.async(group: group) {
            self.networkRequest(sleepTime:2, closure: {
                print("2")
                semaphore.signal()
            })
        }
        
        queue.async(group: group) {
            self.networkRequest(sleepTime:2, closure: {
                print("3")
                semaphore.signal()
            })
        }
        
        group.notify(queue: queue) {
            semaphore.wait()
            semaphore.wait()
            semaphore.wait()
            print("all done")
        }
    }

多個(gè)相關(guān)請(qǐng)求順序執(zhí)行

有時(shí)候開(kāi)發(fā)中也會(huì)遇到利用網(wǎng)絡(luò)請(qǐng)求A返回的的數(shù)據(jù)來(lái)進(jìn)行網(wǎng)絡(luò)請(qǐng)求B痒留,以前也是十分膚淺地利用嵌套兜看,雖然簡(jiǎn)單可行而且可以減少中間變量,但是出現(xiàn)過(guò)多嵌套代碼不易debug狭瞎。這里也是可以利用 DispatchSemaphore 信號(hào)量。網(wǎng)絡(luò)請(qǐng)求A完成后 signal搏予,而網(wǎng)絡(luò)請(qǐng)求B發(fā)起前 wait熊锭。

    // 利用 semaphore 來(lái)控制
    func gcd_line_request() {
        let semaphore = DispatchSemaphore.init(value: 0)
        let group = DispatchGroup.init()
        let queue = DispatchQueue.global()
        
        queue.async(group: group) {
            self.networkRequest(sleepTime:1, closure: {
                print("1")
                semaphore.signal()
            })
        }
        
        queue.async(group: group) {
            semaphore.wait()
            self.networkRequest(sleepTime:2, closure: {
                print("2")
            })
        }
    }

當(dāng)然也可以利用RAC,在A請(qǐng)求完成后發(fā)送信號(hào)喚醒B執(zhí)行即可雪侥,還可以傳遞參數(shù)碗殷。

  // 利用 rac 來(lái)控制
  func rac_request() {

      let (requestA, observerA) = Signal<Bool, NoError>.pipe()

      self.networkRequest(sleepTime: 1) {
          print("網(wǎng)絡(luò)請(qǐng)求A完成")
          observerA.send(value: true) //網(wǎng)絡(luò)請(qǐng)求完成并且是成功的
          observerA.sendCompleted()
      }

      requestA.observeValues { (success) in
          if success {
              self.networkRequest(sleepTime: 1, closure: {
                  print("網(wǎng)絡(luò)請(qǐng)求B完成")
              })
          }
      }
  }

順便說(shuō)說(shuō)柵欄函數(shù) dispatch_barrier_async

這是可以在并行隊(duì)列中插入一個(gè)操作,例如任務(wù)1234都是并行的速缨,如果在代碼中12和34插入dispatch_barrier_async 則可以保證 dispatch_barrier_async 中的內(nèi)容在12后锌妻、34前執(zhí)行。

    func test() {
        let group = DispatchGroup.init()
        let queue = DispatchQueue.init(label: "xQ")
        
        queue.async(group: group) {
            print("1 start")
        }
        
        queue.async(group: group) {
            print("2 start")
        }
        
        queue.async(group: group, flags: .barrier) {
            print("5 start")
        }
        
        queue.async(group: group) {
            print("3 start")
        }
        
        queue.async(group: group) {
            print("4 start")
        }
    }

這里可以保證輸出為 12/21 5 34/43 這樣的順序旬牲,5肯定夾在中間仿粹。
不過(guò)注意這里有個(gè)十分坑的地方:對(duì)于 DispatchQueue.global() 這個(gè)函數(shù)不起效搁吓!
在 swift 文檔中并沒(méi)有提到,我是在看 OC 文檔中發(fā)現(xiàn)的解釋吭历,對(duì) DispatchQueue.global() 不起效堕仔,僅相當(dāng)于 dispatch_asyncdispatch_barrier_async 只對(duì)自己創(chuàng)建的隊(duì)列才生效晌区。

The queue you specify should be a concurrent queue that you create yourself using the dispatch_queue_create function. If the queue you pass to this function is a serial queue or one of the global concurrent queues, this function behaves like the dispatch_async function.

最后說(shuō)一句摩骨,swift3 中的 GCD 幾乎全部換新,具體使用必須看官方文件朗若。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末恼五,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子哭懈,更是在濱河造成了極大的恐慌灾馒,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件银伟,死亡現(xiàn)場(chǎng)離奇詭異你虹,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)彤避,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門傅物,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人琉预,你說(shuō)我怎么就攤上這事董饰。” “怎么了圆米?”我有些...
    開(kāi)封第一講書人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵卒暂,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我娄帖,道長(zhǎng)也祠,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任近速,我火速辦了婚禮诈嘿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘削葱。我一直安慰自己奖亚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布析砸。 她就那樣靜靜地躺著昔字,像睡著了一般。 火紅的嫁衣襯著肌膚如雪首繁。 梳的紋絲不亂的頭發(fā)上作郭,一...
    開(kāi)封第一講書人閱讀 52,268評(píng)論 1 309
  • 那天陨囊,我揣著相機(jī)與錄音,去河邊找鬼所坯。 笑死谆扎,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的芹助。 我是一名探鬼主播堂湖,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼状土!你這毒婦竟也來(lái)了无蜂?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蒙谓,失蹤者是張志新(化名)和其女友劉穎斥季,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體累驮,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡酣倾,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了谤专。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片躁锡。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖置侍,靈堂內(nèi)的尸體忽然破棺而出映之,到底是詐尸還是另有隱情,我是刑警寧澤蜡坊,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布杠输,位于F島的核電站,受9級(jí)特大地震影響秕衙,放射性物質(zhì)發(fā)生泄漏蠢甲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一据忘、第九天 我趴在偏房一處隱蔽的房頂上張望鹦牛。 院中可真熱鬧,春花似錦若河、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至辈赋,卻和暖如春鲫忍,著一層夾襖步出監(jiān)牢的瞬間膏燕,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工悟民, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坝辫,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓射亏,卻偏偏與公主長(zhǎng)得像近忙,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子智润,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

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

  • 談到iOS多線程及舍,一般都會(huì)談到四種方式:pthread、NSThread窟绷、GCD和NSOperation锯玛。其中,蘋...
    攻城獅GG閱讀 274評(píng)論 0 3
  • 一. 重點(diǎn): 1.dispatch_queue_create(生成Dispatch Queue) 2.Main D...
    BestJoker閱讀 1,587評(píng)論 2 2
  • Quality of Service(QoS) 這是在iOS8之后提供的新功能兼蜈,蘋果提供了幾個(gè)Quality of...
    樹(shù)下老男孩閱讀 15,689評(píng)論 10 132
  • 英譯中 辦公室小談—談?wù)撎鞖?梅利莎:嗨攘残,米夏艾爾∥辏快點(diǎn)進(jìn)來(lái)歼郭,外面傾盆大雨。 米夏艾爾:奧钥平, 你好实撒,梅利莎。你也要...
    明睿周一方閱讀 336評(píng)論 0 0
  • 在她加我QQ之前负敏,我跟她沒(méi)有什么交流,唯一說(shuō)過(guò)的話就是問(wèn)她有什么英語(yǔ)作業(yè)秘蛇。后來(lái)高二快會(huì)考的前幾天晚上其做,我在玩手機(jī),...
    miss豆芽?jī)?/span>閱讀 220評(píng)論 0 0