Swift4中如何循环逐个执行异步方法?当前实现并发执行异常
Hey there! Let's break down why your current code isn't working as expected, then walk through solid solutions to get those requests running one after another.
What's Going Wrong
Your OperationQueue is correctly set to run operations serially (maxConcurrentOperationCount = 1), but here's the catch: each operation's block only kicks off the asynchronous performAsyncRequests call, then immediately finishes. Since the operation doesn't wait for the async request to complete, the queue moves right to the next operation—resulting in all your requests firing off in parallel anyway.
Fix 1: Make Operations Wait for Async Requests
Use a DispatchSemaphore to force each operation to pause until the async request finishes. This ensures the operation only marks itself as complete once the request is done, keeping the queue's serial behavior intact.
let queue = OperationQueue() queue.maxConcurrentOperationCount = 1 for i in 0..<results.count { queue.addOperation { print("Operation \(i) started") let semaphore = DispatchSemaphore(value: 0) self.performAsyncRequests(completion: { (result) in print("Request \(i) completed") semaphore.signal() // Tell the semaphore the request is done }) semaphore.wait() // Pause the operation until the request finishes } } // Wait for all operations to finish, then update UI on main thread queue.waitUntilAllOperationsAreFinished() DispatchQueue.main.async { print("All requests completed") self.reloadTableView() }
Fix 2: Use Operation Dependencies
If you need more flexibility (like adjusting execution order later), you can explicitly set dependencies between operations. Each new operation will only start once the previous one (and its async request) is fully complete.
let queue = OperationQueue() queue.maxConcurrentOperationCount = 1 var previousOperation: Operation? = nil for i in 0..<results.count { let operation = BlockOperation { [weak self] in guard let self = self else { return } print("Operation \(i) started") let semaphore = DispatchSemaphore(value: 0) self.performAsyncRequests(completion: { (result) in print("Request \(i) completed") semaphore.signal() }) semaphore.wait() } // Make this operation depend on the previous one if let prevOp = previousOperation { operation.addDependency(prevOp) } queue.addOperation(operation) previousOperation = operation } queue.waitUntilAllOperationsAreFinished() DispatchQueue.main.async { print("All requests completed") self.reloadTableView() }
Fix 3: Swift Async/Await (Recommended for Swift 5.5+)
If your project supports Swift 5.5 or later, Async/Await simplifies this drastically—no semaphores or operation dependencies needed. First, wrap your existing async method to support async/await:
// Replace ResultType with your actual result type func performAsyncRequests() async -> ResultType { return await withCheckedContinuation { continuation in self.performAsyncRequests(completion: { result in continuation.resume(returning: result) }) } }
Then run your requests in sequence with a simple loop:
Task { for i in 0..<results.count { print("Request \(i) started") let result = await self.performAsyncRequests() print("Request \(i) completed") } // Update UI on the main thread await MainActor.run { print("All requests completed") self.reloadTableView() } }
The await keyword ensures the loop waits for each request to finish before moving to the next iteration—clean, readable, and exactly what you need.
内容的提问来源于stack exchange,提问作者Dan Abnormal

