You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS中如何在for循环内等待进程完成后再进入下一次迭代?

Solution for Synchronous Iteration with Asynchronous NSURLSession Tasks

Got it, let's break down how to fix this. Your current code fires off all 5 NSURLSessionDataTasks at once because they run asynchronously—so the for loop doesn't pause for each task to finish before moving to the next iteration. Here are a few reliable approaches, tailored to different iOS version requirements:

1. Using Dispatch Semaphores (Legacy Compatible)

This works for all iOS versions and uses GCD to block the loop until each async task completes. Critical note: Never run this on the main thread (it'll freeze your app's UI). Always use a background queue for this kind of synchronous waiting.

dispatch_queue_t backgroundQueue = dispatch_queue_create("com.yourdomain.requestQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(backgroundQueue, ^{
    for (int i = 0; i < 5; i++) {
        NSLog(@"%d Iteration started", i);
        
        // Create a semaphore to wait for the task to finish
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
        
        [[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            NSLog(@"%d iteration completed ", i);
            // Signal the semaphore that we're done
            dispatch_semaphore_signal(semaphore);
        }] resume];
        
        // Wait until the semaphore is signaled
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        dispatch_release(semaphore); // Skip this line if using ARC
    }
});

2. Using OperationQueue (Controlled Concurrency)

If you prefer an object-oriented approach, OperationQueue lets you queue tasks and enforce sequential execution by setting maxConcurrentOperationCount to 1. Each network task is wrapped in an NSBlockOperation:

NSOperationQueue *serialQueue = [[NSOperationQueue alloc] init];
serialQueue.maxConcurrentOperationCount = 1; // Only one task runs at a time

for (int i = 0; i < 5; i++) {
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"%d Iteration started", i);
        
        // Use a semaphore inside the operation to wait for the async task
        dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
        
        [[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            NSLog(@"%d iteration completed ", i);
            dispatch_semaphore_signal(semaphore);
        }] resume];
        
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        dispatch_release(semaphore); // Skip this line if using ARC
    }];
    
    [serialQueue addOperation:operation];
}

3. Async/Await (Modern iOS 15+)

If you're targeting iOS 15 or later, Objective-C now supports async/await, which makes this code much cleaner and avoids manual semaphores. First, wrap the dataTaskWithRequest: call into an async helper method:

// Declare an async helper method
- (NSData * _Nullable)fetchDataWithRequest:(NSURLRequest *)request error:(NSError **)error async {
    __block NSData *resultData;
    __block NSError *resultError;
    
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    [[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable taskError) {
        resultData = data;
        resultError = taskError;
        dispatch_semaphore_signal(semaphore);
    }] resume];
    
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    if (error) *error = resultError;
    return resultData;
}

// Then use it in your loop (must be called from an async context)
- (void)runSequentialTasks async {
    for (int i = 0; i < 5; i++) {
        NSLog(@"%d Iteration started", i);
        NSError *error;
        NSData *data = [self fetchDataWithRequest:request error:&error];
        NSLog(@"%d iteration completed ", i);
        
        if (error) {
            // Handle error if needed
            NSLog(@"Error in iteration %d: %@", i, error.localizedDescription);
        }
    }
}

Bonus: Swift Version (iOS 13+)

If you're using Swift, async/await is even more straightforward (available in iOS 13+ with Combine, or iOS 15+ with native async/await):

// iOS 15+ native async/await
func runSequentialTasks() async {
    for i in 0..<5 {
        print("\(i) Iteration started")
        do {
            let (data, response) = try await URLSession.shared.data(for: request)
            print("\(i) iteration completed")
        } catch {
            print("Error in iteration \(i): \(error.localizedDescription)")
        }
    }
}

// Call it from an async context, e.g.:
// Task {
//     await runSequentialTasks()
// }

Key Tips:

  • Avoid blocking the main thread: All these approaches should run on a background queue/async context to keep your app responsive.
  • Add timeouts: If you don't want to wait indefinitely, replace DISPATCH_TIME_FOREVER with a specific timeout (e.g., dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC) for 10 seconds).
  • Don't skip error handling: Always add checks for network errors to avoid silent failures in your iterations.

内容的提问来源于stack exchange,提问作者Anil Kumar R

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:17:47