淺談如何在項目中處理頁面中的多個網絡請求

在開發中很多時候會有這樣的場景,同一個界面有多個請求,而且要在這幾個請求都成功返回的時候再去進行下一操作,對于這種場景,如何來設計請求操作呢?今天我們就來討論一下有哪幾種方案。

分析:

在網絡請求的開發中,經常會遇到兩種情況,一種是多個請求結束后統一操作,在一個界面需要同時請求多種數據,比如列表數據、廣告數據等,全部請求到后再一起刷新界面。另一種是多個請求順序執行,比如必須先請求個人信息,然后根據個人信息請求相關內容。這些要求對于普通的操作是可以做到并發控制和依賴操作的,但是對于網絡請求這種需要時間的請求來說,效果往往與預期的不一樣。因為網絡請求是異步的,并不知道什么時候網絡請求。很多開發人員為了省事,對于網絡請求必須滿足一定順序這種情況,一般都是嵌套網絡請求,即一個網絡請求成功之后再請求另一個網絡請求,雖然采用嵌套請求的方式能解決此問題,但存在很多問題,如:其中一個請求失敗會導致后續請求無法正常進行、多個請求在時間上沒有復用,即無并發性。來看一下下面幾種方案:

dispatch_semaphore 信號量

信號量是一個整數,在創建的時候會有一個初始值,這個初始值往往代表我要控制的同時操作的并發數。
在操作中,對信號量會有兩種操作:信號通知與等待。信號通知時,信號量會+1,等待時,如果信號量大于0,則會將信號量-1,否則,會等待直到信號量大于0。什么時候會大于零呢?往往是在之前某個操作結束后,我們發出信號通知,讓信號量+1。

在 GCD 中,提供了以下這么幾個函數,可用于請求同步等處理,模擬同步請求:

// 創建一個信號量(semaphore)
dispatch_semaphore_t semaphore = dispatch_semaphore_create(value);
// 等待,直到信號量大于0時,即可操作,同時將信號量-1
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// 信號通知,即讓信號量+1
dispatch_semaphore_signal(semaphore);

在使用的時候,往往會創建一個信號量,然后進行多個操作,每次操作都等待信號量大于0再操作,同時信號量-1,操作完后將信號量+1。當信號量就減小到0了,這時候wait操作會起作用,DISPATCH_TIME_FOREVER 表示會永遠等待,一直等到信號量大于0,也就是有操作完成了,將信號量+1了,這時候才可以結束等待,進行操作,并且將信號量-1,這樣新的任務又要等待。

下面我們展示一段代碼來模擬同步請求:

image.png

從打印結果可以看出,在每個請求開始之前,我們創建一個信號量,初始為0,在請求操作之后,我們設一個 dispatch_semaphore_wait,在請求到結果之后,再將信號量+1,也即是 dispatch_semaphore_signal。這樣做的目的是保證在請求結果沒有返回之前,一直讓線程等待在那里,這樣一個線程的任務一直在等待,就不會算作完成,notify 的內容也就不會執行了,直到每個請求的結果都返回了,線程任務才能夠結束,這時候 notify 也才能夠執行。

dispatch_group(組)

可以使用 dispatch_group_async 函數將多個任務關聯到一個 dispatch_group 和相應的 queue 中,dispatch_group 會并發地同時執行這些任務。而且 dispatch_group 可以用來阻塞一個線程,直到 dispatch_group 關聯的所有的任務完成執行。有時候必須等待任務完成的結果,然后才能繼續后面的處理。

主要使用如下兩個函數:

dispatch_group_enter(group);
dispatch_group_leave(group);

注意:
以上這兩個函數必須配對使用,否則 dispatch_group_notify 不會觸發。

下面我們展示一段代碼來模擬同步請求:

image.png

dispatch_group 會等和它關聯的所有的 dispatch_queue_t 上的任務都執行完畢才會發出同步信號,dispathc_group_notify 的代碼塊 block 會被執行。從控制臺的打印結構可以看出,如果將上面三個操作改成真實的網絡操作后,這個簡單的做法會變得無效,因為網絡請求需要時間,而線程的執行并不會等待請求完成后才真正算作完成,而是只負責將請求發出去,線程就認為自己的任務算完成了,當三個請求都發送出去,就會執行 dispathc_group_notify 中的內容,但請求結果返回的時間是不一定的,也就導致界面都刷新了,請求才返回,這就是無效的。

image.png

notify 的作用就是在 group 中的其他操作全部完成后,再操作自己的內容,所以我們會看到上面事件 A、B、C 執行之后,才執行事件 E。
dispatch_async 相比,當我們調用 ndispatch_group_enter 后再調用 ndispatch_group_level 時,dispatch_group_notifydispatch_group_wait 會收到同步信號;這個特點使得它非常適合處理異步任務的同步當異步任務開始前調用 dispatch_group_enter 異步任務結束后調用 dispatch_group_leve;

NSOperationQueue

NSOperationQueue 只有兩種隊列,即主隊列和并行隊列。通過 [[NSOperationQueue alloc] init]; 創建的隊列都是并行隊列,并且可以將一個或多個 NSOperation 對象放到隊列中去執行,而且是異步執行的,一個 NSOperation 對象可以通過調用 start 方法來執行任務,但是默認是同步執行的。則主隊列通過 [NSOperationQueue mainQueue]; 獲得,而且其中所有 NSOperation 都會在主線程中執行。

當然也可以利用 NSOperationQueue 的線程依賴,當某個 NSOperation 對象依賴于其它 NSOperation 對象的完成時,就可以通過 addDependency 方法添加一個或者多個依賴的對象,只有所有依賴的對象都已經完成操作,當前 NSOperation 對象才會開始執行操作。需要先添加依賴關系,再將操作添加到隊列中。另外,通過 removeDependency 方法來刪除依賴對象。

結論

在開發過程中,我們應盡量避免發送同步請求;假設我們一個頁面需要同時進行多個請求,他們之間倒是不要求順序關系,但是要求等他們都請求完畢了再進行界面刷新或者其他什么操作。并且在某個操作依賴于其他幾個任務的完成時,采用 dispatch_group or dispatch_semaphore 來實現同步等處理。如果在某個操作依賴于其他幾個任務的完成,可以考慮使用 NSOperationQueue 的線程之間依賴。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,818評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,185評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,656評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,647評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,446評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,951評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,041評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,189評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,718評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,800評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,419評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,420評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,755評論 2 371

推薦閱讀更多精彩內容

  • 1.屬性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作...
    曾令偉閱讀 1,076評論 0 10
  • iOS面試小貼士 ———————————————回答好下面的足夠了------------------------...
    不言不愛閱讀 1,996評論 0 7
  • 多線程、特別是NSOperation 和 GCD 的內部原理。運行時機制的原理和運用場景。SDWebImage的原...
    LZM輪回閱讀 2,023評論 0 12
  • 史上最全的iOS面試題及答案 iOS面試小貼士———————————————回答好下面的足夠了----------...
    Style_偉閱讀 2,372評論 0 35
  • 基礎 1.為什么說Objective-C是一門動態的語言? 所謂的動態類型語言,意思就是類型的檢查是在運行時做的。...
    陽明先生_X自主閱讀 1,029評論 0 17