1. 程式人生 > 實用技巧 >iOS 等待for迴圈裡的非同步任務完成再進行其他操作的一個解決辦法 -- 訊號量+序列佇列卡for小迴圈

iOS 等待for迴圈裡的非同步任務完成再進行其他操作的一個解決辦法 -- 訊號量+序列佇列卡for小迴圈

轉自:https://blog.csdn.net/qq_34417314/article/details/80449484

for迴圈裡的非同步操作

開發中經常會遇到這樣一些情況,比如:
1.登入失敗後的多次登入重連場景。
2.在一個for迴圈遍歷裡,有多種非同步操作,需要在所有的非同步操作完成後,也就是for迴圈的遍歷結束後,再去執行其他操作,但是不能卡主執行緒,這時候就需要用其他方法了。

我遇到的需求是,在一個for迴圈裡有資料庫的查詢操作以及網路請求操作,然後將資料庫的查詢和網路請求的結果新增到一個臨時陣列中,最後等for迴圈結束後,將臨時陣列通過block回傳出去。
解決辦法如下:

- 序列佇列配合訊號量

因為for迴圈不能卡主執行緒,所以我們首先要建立一個序列的佇列(併發的不可以),然後通過訊號量來控制for迴圈,下面是模擬的一個操作:

printf("處理前建立訊號量,開始迴圈非同步請求操作\n");
 
// 1.建立一個序列佇列,保證for迴圈依次執行
        dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
 
// 2.非同步執行任務
dispatch_async(serialQueue, ^{
    // 3.建立一個數目為1的訊號量,用於“卡”for迴圈,等上次迴圈結束在執行下一次的for迴圈
dispatch_semaphore_t sema = dispatch_semaphore_create(1); for (int i = 0; i<5; i++) { // 開始執行for迴圈,讓訊號量-1,這樣下次操作須等訊號量>=0才會繼續,否則下次操作將永久停止 dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); printf("訊號量等待中\n"); // 模擬一個非同步任務 NSMutableURLRequest *urlRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"
https://github.com"]]; NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:urlRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { // 本次for迴圈的非同步任務執行完畢,這時候要發一個訊號,若不發,下次操作將永遠不會觸發 [tampArray addObject:@(i)]; NSLog(@"本次耗時操作完成,訊號量+1 %@\n",[NSThread currentThread]); dispatch_semaphore_signal(sema); }]; [dataTask resume]; } NSLog(@"其他操作"); for (NSNumber *num in tampArray) { NSLog(@"所有操作完成後的操作---> %@\n",num); } });

以上就是一個簡單的卡for迴圈的例項