iOS面試題--如何在專案中處理頁面中的多個網路請求
面試題: 如何在專案中處理頁面中的多個網路請求。 在開發中很多時候會有這樣的場景,同一個介面有多個請求,而且要在這幾個請求都成功返回的時候再去進行下一操作,對於這種場景,如何來設計請求操作呢?今天我們就來討論一下有哪幾種方案。
分析: 在網路請求的開發中,經常會遇到兩種情況,一種是多個請求結束後統一操作,在一個介面需要同時請求多種資料,比如列表資料、廣告資料等,全部請求到後再一起重新整理介面。另一種是多個請求順序執行,比如必須先請求個人資訊,然後根據個人資訊請求相關內容。這些要求對於普通的操作是可以做到併發控制和依賴操作的,但是對於網路請求這種需要時間的請求來說,效果往往與預期的不一樣。因為網路請求是非同步的,並不知道什麼時候網路請求。很多開發人員為了省事,對於網路請求必須滿足一定順序這種情況,一般都是巢狀網路請求,即一個網路請求成功之後再請求另一個網路請求,總覺得這麼不做不是一個好的解決方案,來看一下下面幾種方案:
訊號量
訊號量是一個整數,在建立的時候會有一個初始值,這個初始值往往代表我要控制的同時操作的併發數。在操作中,對訊號量會有兩種操作:訊號通知與等待。訊號通知時,訊號量會+1,等待時,如果訊號量大於0,則會將訊號量-1,否則,會等待直到訊號量大於0。什麼時候會大於零呢?往往是在之前某個操作結束後,我們發出訊號通知,讓訊號量+1。
- dispatch_semaphore_create:建立一個訊號量(semaphore)
- dispatch_semaphore_signal:訊號通知,即讓訊號量+1
- dispatch_semaphore_wait:等待,直到訊號量大於0時,即可操作,同時將訊號量-1
在使用的時候,往往會建立一個訊號量,然後進行多個操作,每次操作都等待訊號量大於0再操作,同時訊號量-1,操作完後將訊號量+1。當訊號量就減小到0了,這時候wait操作會起作用,DISPATCH_TIME_FOREVER
NSOperationQueue
NSOperationQueue
只有兩種佇列,即主佇列和並行佇列。通過[[NSOperationQueue alloc] init];
建立的佇列都是並行佇列,並且可以將一個或多個NSOperation物件放到佇列中去執行,而且是非同步執行的,一個NSOperation物件可以通過呼叫start方法來執行任務,但是預設是同步執行的。則主佇列通過[NSOperationQueue mainQueue];
獲得,而且其中所有NSOperation
當然也可以利用NSOperationQueue
的執行緒依賴,當某個NSOperation
物件依賴於其它NSOperation
物件的完成時,就可以通過addDependency
方法新增一個或者多個依賴的物件,只有所有依賴的物件都已經完成操作,當前NSOperation
物件才會開始執行操作。需要先新增依賴關係,再將操作新增到佇列中。另外,通過removeDependency
方法來刪除依賴物件。
dispatch_group_t
可以使用dispatch_group_async
函式將多個任務關聯到一個dispatch_group
和相應的queue
中,dispatch_group
會併發地同時執行這些任務。而且dispatch_group
可以用來阻塞一個執行緒,直到dispatch_group
關聯的所有的任務完成執行。有時候必須等待任務完成的結果,然後才能繼續後面的處理。
多個請求結束後統一操作,最優方案:
假設我們一個頁面需要同時進行多個請求,他們之間倒是不要求順序關係,但是要求等他們都請求完畢了再進行介面重新整理或者其他什麼操作。
一、dispatch_group_t
image.pngdispatch_group
會等和它關聯的所有的dispatch_queue_t
上的任務都執行完畢才會發出同步訊號,dispathc_group_notify
的程式碼塊block會被執行。從控制檯的列印結構可以看出,如果將上面三個操作改成真實的網路操作後,這個簡單的做法會變得無效,因為網路請求需要時間,而執行緒的執行並不會等待請求完成後才真正算作完成,而是隻負責將請求發出去,執行緒就認為自己的任務算完成了,當三個請求都發送出去,就會執行dispathc_group_notify
中的內容,但請求結果返回的時間是不一定的,也就導致介面都重新整理了,請求才返回,這就是無效的。
notify
的作用就是在group
中的其他操作全部完成後,再操作自己的內容,所以我們會看到上面事件A、B、C執行之後,才執行事件E。
和dispatch_async
相比,當我們呼叫n
次dispatch_group_enter
後再呼叫n
次dispatch_group_level
時,dispatch_group_notify
和dispatch_group_wait
會收到同步訊號;這個特點使得它非常適合處理非同步任務的同步當非同步任務開始前呼叫dispatch_group_enter
非同步任務結束後呼叫dispatch_group_leve
;
二、dispatch_semaphore_t
image.png在每個請求開始之前,我們建立一個訊號量,初始為0,在請求操作之後,我們設一個dispatch_semaphore_wait
,在請求到結果之後,再將訊號量+1,也即是dispatch_semaphore_signal
。這樣做的目的是保證在請求結果沒有返回之前,一直讓執行緒等待在那裡,這樣一個執行緒的任務一直在等待,就不會算作完成,notify
的內容也就不會執行了,直到每個請求的結果都返回了,執行緒任務才能夠結束,這時候notify
也才能夠執行。