等待直到带有异步网络请求的swift for循环完成执行

时间:2022-08-23 18:13:52

I would like a for in loop to send off a bunch of network requests to firebase, then pass the data to a new view controller once the the method finishes executing. Here is my code:

我想要一个for in循环向firebase发送一系列网络请求,然后在方法执行完毕后将数据传递给一个新的视图控制器。这是我的代码:

    var datesArray = [String: AnyObject]()

        for key in locationsArray {       
            let ref = Firebase(url: "http://myfirebase.com/" + "\(key.0)")
            ref.observeSingleEventOfType(.Value, withBlock: { snapshot in

                datesArray["\(key.0)"] = snapshot.value

            })
        }

        //Segue to new view controller here, and pass datesArray once it is complete 

I have a couple concerns. First, how do I wait until the for loop is finished and all the network requests are complete? I can't modify the observeSingleEventOfType function, it is part of the firebase SDK. Also, will I create some sort of race condition by trying to access the datesArray from different iterations of the for loop (hope that makes sense)? I've been reading about GCD and NSOperation but I'm a bit lost as this is the first app I've built.

我有几个问题。首先,我如何等到for循环完成并且所有的网络请求都完成之后才进行操作?我不能修改observeSingleEventOfType函数,它是firebase SDK的一部分。另外,我是否要通过尝试从for循环的不同迭代访问datesArray来创建某种竞争条件(希望这是有意义的)?我一直在读GCD和NSOperation,但是我有点迷惑,因为这是我创建的第一个应用。

Note: Locations array is an array containing the keys I need to access in firebase. Also, it's important that the network requests are fired off asynchronously. I just want to wait until ALL the asynchronous requests complete before I pass the datesArray to the next view controller.

注意:location数组是一个数组,其中包含了在firebase中需要访问的键。此外,重要的是网络请求是异步发送的。我只想在将datesArray传递给下一个视图控制器之前等待所有异步请求完成。

7 个解决方案

#1


187  

You can use dispatch groups to fire an asynchronous callback when all your requests finish.

您可以使用分派组在所有请求完成时触发异步回调。

Here's an example in Swift 4.1 (works in Swift 3 too) using dispatch groups to execute a callback asynchronously when multiple networking requests have all finished.

下面是Swift 4.1中的一个示例(也适用于Swift 3),当多个网络请求都完成时,使用分派组异步执行回调。

override func viewDidLoad() {
    super.viewDidLoad()

    let myGroup = DispatchGroup()

    for i in 0 ..< 5 {
        myGroup.enter()

        Alamofire.request("https://httpbin.org/get", parameters: ["foo": "bar"]).responseJSON { response in
            print("Finished request \(i)")
            myGroup.leave()
        }
    }

    myGroup.notify(queue: .main) {
        print("Finished all requests.")
    }
}

Output

输出

Finished request 1
Finished request 0
Finished request 2
Finished request 3
Finished request 4
Finished all requests.

For those using the older Swift 2.3, here's an example using its syntax:

对于使用较旧的Swift 2.3的用户,这里有一个使用其语法的示例:

override func viewDidLoad() {
    super.viewDidLoad()

    let myGroup = dispatch_group_create()

    for i in 0 ..< 5 {
        dispatch_group_enter(myGroup)
        Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"]).responseJSON { response in
            print("Finished request \(i)")
            dispatch_group_leave(self.myGroup)
        }
    }

    dispatch_group_notify(myGroup, dispatch_get_main_queue(), {
        print("Finished all requests.")
    })
}

#2


35  

Xcode 8.3.1 - Swift 3

Xcode 8.3.1 - Swift 3

This is the accepted answer of paulvs, converted to Swift 3:

这是保罗的公认答案,转换为Swift 3:

let myGroup = DispatchGroup()

override func viewDidLoad() {
    super.viewDidLoad()

    for i in 0 ..< 5 {
        myGroup.enter()
        Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"]).responseJSON { response in
            print("Finished request \(i)")
            myGroup.leave()
        }
    }

    myGroup.notify(queue: DispatchQueue.main, execute: {
        print("Finished all requests.")
    })
}

#3


5  

You will need to use semaphores for this purpose.

为此,您需要使用信号量。

 //Create the semaphore with count equal to the number of requests that will be made.
let semaphore = dispatch_semaphore_create(locationsArray.count)

        for key in locationsArray {       
            let ref = Firebase(url: "http://myfirebase.com/" + "\(key.0)")
            ref.observeSingleEventOfType(.Value, withBlock: { snapshot in

                datesArray["\(key.0)"] = snapshot.value

               //For each request completed, signal the semaphore
               dispatch_semaphore_signal(semaphore)


            })
        }

       //Wait on the semaphore until all requests are completed
      let timeoutLengthInNanoSeconds: Int64 = 10000000000  //Adjust the timeout to suit your case
      let timeout = dispatch_time(DISPATCH_TIME_NOW, timeoutLengthInNanoSeconds)

      dispatch_semaphore_wait(semaphore, timeout)

     //When you reach here all request would have been completed or timeout would have occurred.

#4


3  

Swift 3: You could also use semaphores on this way. It results very helpful, besides you can keep exact track on when and what processes are completed. This has been extracted from my code:

斯威夫特3:你也可以用这种方式使用信号灯。它的结果非常有用,而且您还可以精确地跟踪什么时候以及什么过程完成。这是从我的代码中摘录的:

    //You have to create your own queue or if you need the Default queue
    let persons = persistentContainer.viewContext.persons
    print("How many persons on database: \(persons.count())")
    let numberOfPersons = persons.count()

    for eachPerson in persons{
        queuePersonDetail.async {
            self.getPersonDetailAndSave(personId: eachPerson.personId){person2, error in
                print("Person detail: \(person2?.fullName)")
                //When we get the completionHandler we send the signal
                semaphorePersonDetailAndSave.signal()
            }
        }
    }

    //Here we will wait
    for i in 0..<numberOfPersons{
        semaphorePersonDetailAndSave.wait()
        NSLog("\(i + 1)/\(persons.count()) completed")
    }
    //And here the flow continues...

#5


3  

Swift 3 or 4

斯威夫特3或4

If you don't care about orders, use @paulvs's answer, it works perfectly.

如果你不关心订单,使用@paulvs的答案,它非常有效。

else just in case if anyone wants to get the result in order instead of fire them concurrently, here is the code.

否则,如果有人想要得到有序的结果而不是同时触发它们,这里是代码。

let dispatchGroup = DispatchGroup()
let dispatchQueue = DispatchQueue(label: "taskQueue")
let dispatchSemaphore = DispatchSemaphore(value: 0)

dispatchQueue.async {

    // use array categories as an example.
    for c in self.categories {

        if let id = c.categoryId {

            dispatchGroup.enter()

            self.downloadProductsByCategory(categoryId: id) { success, data in

                if success, let products = data {

                    self.products.append(products)
                }

                dispatchSemaphore.signal()
                dispatchGroup.leave()
            }

            dispatchSemaphore.wait()
        }
    }
}

dispatchGroup.notify(queue: dispatchQueue) {

    DispatchQueue.main.async {

        self.refreshOrderTable { _ in

            self.productCollectionView.reloadData()
        }
    }
}

#6


3  

Details

Xcode 9.2, Swift 4

Xcode 9.2,斯威夫特4

Solution

class AsyncOperation {

    typealias NumberOfPendingActions = Int
    typealias DispatchQueueOfReturningValue = DispatchQueue
    typealias CompleteClosure = ()->()

    private let dispatchQueue: DispatchQueue
    private var semaphore: DispatchSemaphore

    private var numberOfPendingActionsQueue: DispatchQueue
    public private(set) var numberOfPendingActions = 0

    var whenCompleteAll: (()->())?

    init(numberOfSimultaneousActions: Int, dispatchQueueLabel: String) {
        dispatchQueue = DispatchQueue(label: dispatchQueueLabel)
        semaphore = DispatchSemaphore(value: numberOfSimultaneousActions)
        numberOfPendingActionsQueue = DispatchQueue(label: dispatchQueueLabel + "_numberOfPendingActionsQueue")
    }

    func run(closure: @escaping (@escaping CompleteClosure)->()) {

        self.numberOfPendingActionsQueue.sync {
            self.numberOfPendingActions += 1
        }

        dispatchQueue.async {
            self.semaphore.wait()
            closure {
                self.numberOfPendingActionsQueue.sync {
                    self.numberOfPendingActions -= 1
                    if self.numberOfPendingActions == 0 {
                        self.whenCompleteAll?()
                    }
                }
                self.semaphore.signal()
            }
        }
    }
}

Usage

let asyncOperation = AsyncOperation(numberOfSimultaneousActions: 1, dispatchQueueLabel: "AnyString")
asyncOperation.whenCompleteAll = {
    print("All Done")
}
for i in 0...5 {
    print("\(i)")
    asyncOperation.run{ completeClosure in
        // add any (sync/async) code
        //..

        // Make signal that this closure finished
        completeClosure()
    }
}

Full sample

import UIKit

class ViewController: UIViewController {

    let asyncOperation = AsyncOperation(numberOfSimultaneousActions: 3, dispatchQueueLabel: "AnyString")
    let button = UIButton(frame: CGRect(x: 50, y: 80, width: 100, height: 40))
    let label = UILabel(frame: CGRect(x: 180, y: 50, width: 150, height: 100))

    var counter = 1
    var labelCounter = 0

    override func viewDidLoad() {
        super.viewDidLoad()

        button.setTitle("Button", for: .normal)
        button.setTitleColor(.blue, for: .normal)
        button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
        label.text = "\(labelCounter)"
        label.numberOfLines = 2
        label.textAlignment = .natural
        view.addSubview(button)
        view.addSubview(label)
    }

    @objc func buttonTapped() {
        //sample1()
        sample2()
    }

    func sample1() {
        print("Sample 1")
        labelCounter += 1
        label.text = "button tapped \(labelCounter) times"

        print("Button tapped at: \(Date())")
        asyncOperation.whenCompleteAll = {
            print("All Done")
        }
        asyncOperation.run{ completeClosure in
            let counter = self.counter
            print("     - Loading action \(counter) strat at \(Date())")
            self.counter += 1

            DispatchQueue.global(qos: .background).async {
                sleep(1)
                print("     - Loading action \(counter) end at \(Date())")
                completeClosure()
            }
        }
    }

    func sample2() {
        print("Sample 2")
        label.text = ""
        asyncOperation.whenCompleteAll = {
            print("All Done")
        }

        for i in 0...5 {
            asyncOperation.run{ completeClosure in
                let counter = self.counter
                print("     - Loading action \(counter) strat at \(Date())")
                self.counter += 1

                DispatchQueue.global(qos: .background).async {
                    sleep(UInt32(i+i))
                    print("     - Loading action \(counter) end at \(Date())")
                    completeClosure()
                }
            }
        }

    }
}

Results

Sample 1

示例1

等待直到带有异步网络请求的swift for循环完成执行

Sample 2

示例2

等待直到带有异步网络请求的swift for循环完成执行

#7


0  

Dispatch group is good but the order of sent requests is random.

分派组是好的,但是发送请求的顺序是随机的。

Finished request 1
Finished request 0
Finished request 2

In my project case, each requests needed to be launch is the right order. If this could help someone :

在我的项目中,需要启动的每个请求都是正确的顺序。如果这能帮助某人:

public class RequestItem: NSObject {
    public var urlToCall: String = ""
    public var method: HTTPMethod = .get
    public var params: [String: String] = [:]
    public var headers: [String: String] = [:]
}


public func trySendRequestsNotSent (trySendRequestsNotSentCompletionHandler: @escaping ([Error]) -> () = { _ in }) {

    // If there is requests
    if !requestItemsToSend.isEmpty {
        let requestItemsToSendCopy = requestItemsToSend

        NSLog("Send list started")
        launchRequestsInOrder(requestItemsToSendCopy, 0, [], launchRequestsInOrderCompletionBlock: { index, errors in
            trySendRequestsNotSentCompletionHandler(errors)
        })
    }
    else {
        trySendRequestsNotSentCompletionHandler([])
    }
}

private func launchRequestsInOrder (_ requestItemsToSend: [RequestItem], _ index: Int, _ errors: [Error], launchRequestsInOrderCompletionBlock: @escaping (_ index: Int, _ errors: [Error] ) -> Void) {

    executeRequest(requestItemsToSend, index, errors, executeRequestCompletionBlock: { currentIndex, errors in
        if currentIndex < requestItemsToSend.count {
            // We didn't reach last request, launch next request
            self.launchRequestsInOrder(requestItemsToSend, currentIndex, errors, launchRequestsInOrderCompletionBlock: { index, errors in

                launchRequestsInOrderCompletionBlock(currentIndex, errors)
            })
        }
        else {
            // We parse and send all requests
            NSLog("Send list finished")
            launchRequestsInOrderCompletionBlock(currentIndex, errors)
        }
    })
}

private func executeRequest (_ requestItemsToSend: [RequestItem], _ index: Int, _ errors: [Error], executeRequestCompletionBlock: @escaping (_ index: Int, _ errors: [Error]) -> Void) {
    NSLog("Send request %d", index)
    Alamofire.request(requestItemsToSend[index].urlToCall, method: requestItemsToSend[index].method, parameters: requestItemsToSend[index].params, headers: requestItemsToSend[index].headers).responseJSON { response in

        var errors: [Error] = errors
        switch response.result {
        case .success:
            // Request sended successfully, we can remove it from not sended request array
            self.requestItemsToSend.remove(at: index)
            break
        case .failure:
            // Still not send we append arror
            errors.append(response.result.error!)
            break
        }
        NSLog("Receive request %d", index)
        executeRequestCompletionBlock(index+1, errors)
    }
}

Call :

电话:

trySendRequestsNotSent()

Result :

结果:

Send list started
Send request 0
Receive request 0
Send request 1
Receive request 1
Send request 2
Receive request 2
...
Send list finished

See for more infos : Gist

看更多信息:要点

#1


187  

You can use dispatch groups to fire an asynchronous callback when all your requests finish.

您可以使用分派组在所有请求完成时触发异步回调。

Here's an example in Swift 4.1 (works in Swift 3 too) using dispatch groups to execute a callback asynchronously when multiple networking requests have all finished.

下面是Swift 4.1中的一个示例(也适用于Swift 3),当多个网络请求都完成时,使用分派组异步执行回调。

override func viewDidLoad() {
    super.viewDidLoad()

    let myGroup = DispatchGroup()

    for i in 0 ..< 5 {
        myGroup.enter()

        Alamofire.request("https://httpbin.org/get", parameters: ["foo": "bar"]).responseJSON { response in
            print("Finished request \(i)")
            myGroup.leave()
        }
    }

    myGroup.notify(queue: .main) {
        print("Finished all requests.")
    }
}

Output

输出

Finished request 1
Finished request 0
Finished request 2
Finished request 3
Finished request 4
Finished all requests.

For those using the older Swift 2.3, here's an example using its syntax:

对于使用较旧的Swift 2.3的用户,这里有一个使用其语法的示例:

override func viewDidLoad() {
    super.viewDidLoad()

    let myGroup = dispatch_group_create()

    for i in 0 ..< 5 {
        dispatch_group_enter(myGroup)
        Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"]).responseJSON { response in
            print("Finished request \(i)")
            dispatch_group_leave(self.myGroup)
        }
    }

    dispatch_group_notify(myGroup, dispatch_get_main_queue(), {
        print("Finished all requests.")
    })
}

#2


35  

Xcode 8.3.1 - Swift 3

Xcode 8.3.1 - Swift 3

This is the accepted answer of paulvs, converted to Swift 3:

这是保罗的公认答案,转换为Swift 3:

let myGroup = DispatchGroup()

override func viewDidLoad() {
    super.viewDidLoad()

    for i in 0 ..< 5 {
        myGroup.enter()
        Alamofire.request(.GET, "https://httpbin.org/get", parameters: ["foo": "bar"]).responseJSON { response in
            print("Finished request \(i)")
            myGroup.leave()
        }
    }

    myGroup.notify(queue: DispatchQueue.main, execute: {
        print("Finished all requests.")
    })
}

#3


5  

You will need to use semaphores for this purpose.

为此,您需要使用信号量。

 //Create the semaphore with count equal to the number of requests that will be made.
let semaphore = dispatch_semaphore_create(locationsArray.count)

        for key in locationsArray {       
            let ref = Firebase(url: "http://myfirebase.com/" + "\(key.0)")
            ref.observeSingleEventOfType(.Value, withBlock: { snapshot in

                datesArray["\(key.0)"] = snapshot.value

               //For each request completed, signal the semaphore
               dispatch_semaphore_signal(semaphore)


            })
        }

       //Wait on the semaphore until all requests are completed
      let timeoutLengthInNanoSeconds: Int64 = 10000000000  //Adjust the timeout to suit your case
      let timeout = dispatch_time(DISPATCH_TIME_NOW, timeoutLengthInNanoSeconds)

      dispatch_semaphore_wait(semaphore, timeout)

     //When you reach here all request would have been completed or timeout would have occurred.

#4


3  

Swift 3: You could also use semaphores on this way. It results very helpful, besides you can keep exact track on when and what processes are completed. This has been extracted from my code:

斯威夫特3:你也可以用这种方式使用信号灯。它的结果非常有用,而且您还可以精确地跟踪什么时候以及什么过程完成。这是从我的代码中摘录的:

    //You have to create your own queue or if you need the Default queue
    let persons = persistentContainer.viewContext.persons
    print("How many persons on database: \(persons.count())")
    let numberOfPersons = persons.count()

    for eachPerson in persons{
        queuePersonDetail.async {
            self.getPersonDetailAndSave(personId: eachPerson.personId){person2, error in
                print("Person detail: \(person2?.fullName)")
                //When we get the completionHandler we send the signal
                semaphorePersonDetailAndSave.signal()
            }
        }
    }

    //Here we will wait
    for i in 0..<numberOfPersons{
        semaphorePersonDetailAndSave.wait()
        NSLog("\(i + 1)/\(persons.count()) completed")
    }
    //And here the flow continues...

#5


3  

Swift 3 or 4

斯威夫特3或4

If you don't care about orders, use @paulvs's answer, it works perfectly.

如果你不关心订单,使用@paulvs的答案,它非常有效。

else just in case if anyone wants to get the result in order instead of fire them concurrently, here is the code.

否则,如果有人想要得到有序的结果而不是同时触发它们,这里是代码。

let dispatchGroup = DispatchGroup()
let dispatchQueue = DispatchQueue(label: "taskQueue")
let dispatchSemaphore = DispatchSemaphore(value: 0)

dispatchQueue.async {

    // use array categories as an example.
    for c in self.categories {

        if let id = c.categoryId {

            dispatchGroup.enter()

            self.downloadProductsByCategory(categoryId: id) { success, data in

                if success, let products = data {

                    self.products.append(products)
                }

                dispatchSemaphore.signal()
                dispatchGroup.leave()
            }

            dispatchSemaphore.wait()
        }
    }
}

dispatchGroup.notify(queue: dispatchQueue) {

    DispatchQueue.main.async {

        self.refreshOrderTable { _ in

            self.productCollectionView.reloadData()
        }
    }
}

#6


3  

Details

Xcode 9.2, Swift 4

Xcode 9.2,斯威夫特4

Solution

class AsyncOperation {

    typealias NumberOfPendingActions = Int
    typealias DispatchQueueOfReturningValue = DispatchQueue
    typealias CompleteClosure = ()->()

    private let dispatchQueue: DispatchQueue
    private var semaphore: DispatchSemaphore

    private var numberOfPendingActionsQueue: DispatchQueue
    public private(set) var numberOfPendingActions = 0

    var whenCompleteAll: (()->())?

    init(numberOfSimultaneousActions: Int, dispatchQueueLabel: String) {
        dispatchQueue = DispatchQueue(label: dispatchQueueLabel)
        semaphore = DispatchSemaphore(value: numberOfSimultaneousActions)
        numberOfPendingActionsQueue = DispatchQueue(label: dispatchQueueLabel + "_numberOfPendingActionsQueue")
    }

    func run(closure: @escaping (@escaping CompleteClosure)->()) {

        self.numberOfPendingActionsQueue.sync {
            self.numberOfPendingActions += 1
        }

        dispatchQueue.async {
            self.semaphore.wait()
            closure {
                self.numberOfPendingActionsQueue.sync {
                    self.numberOfPendingActions -= 1
                    if self.numberOfPendingActions == 0 {
                        self.whenCompleteAll?()
                    }
                }
                self.semaphore.signal()
            }
        }
    }
}

Usage

let asyncOperation = AsyncOperation(numberOfSimultaneousActions: 1, dispatchQueueLabel: "AnyString")
asyncOperation.whenCompleteAll = {
    print("All Done")
}
for i in 0...5 {
    print("\(i)")
    asyncOperation.run{ completeClosure in
        // add any (sync/async) code
        //..

        // Make signal that this closure finished
        completeClosure()
    }
}

Full sample

import UIKit

class ViewController: UIViewController {

    let asyncOperation = AsyncOperation(numberOfSimultaneousActions: 3, dispatchQueueLabel: "AnyString")
    let button = UIButton(frame: CGRect(x: 50, y: 80, width: 100, height: 40))
    let label = UILabel(frame: CGRect(x: 180, y: 50, width: 150, height: 100))

    var counter = 1
    var labelCounter = 0

    override func viewDidLoad() {
        super.viewDidLoad()

        button.setTitle("Button", for: .normal)
        button.setTitleColor(.blue, for: .normal)
        button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
        label.text = "\(labelCounter)"
        label.numberOfLines = 2
        label.textAlignment = .natural
        view.addSubview(button)
        view.addSubview(label)
    }

    @objc func buttonTapped() {
        //sample1()
        sample2()
    }

    func sample1() {
        print("Sample 1")
        labelCounter += 1
        label.text = "button tapped \(labelCounter) times"

        print("Button tapped at: \(Date())")
        asyncOperation.whenCompleteAll = {
            print("All Done")
        }
        asyncOperation.run{ completeClosure in
            let counter = self.counter
            print("     - Loading action \(counter) strat at \(Date())")
            self.counter += 1

            DispatchQueue.global(qos: .background).async {
                sleep(1)
                print("     - Loading action \(counter) end at \(Date())")
                completeClosure()
            }
        }
    }

    func sample2() {
        print("Sample 2")
        label.text = ""
        asyncOperation.whenCompleteAll = {
            print("All Done")
        }

        for i in 0...5 {
            asyncOperation.run{ completeClosure in
                let counter = self.counter
                print("     - Loading action \(counter) strat at \(Date())")
                self.counter += 1

                DispatchQueue.global(qos: .background).async {
                    sleep(UInt32(i+i))
                    print("     - Loading action \(counter) end at \(Date())")
                    completeClosure()
                }
            }
        }

    }
}

Results

Sample 1

示例1

等待直到带有异步网络请求的swift for循环完成执行

Sample 2

示例2

等待直到带有异步网络请求的swift for循环完成执行

#7


0  

Dispatch group is good but the order of sent requests is random.

分派组是好的,但是发送请求的顺序是随机的。

Finished request 1
Finished request 0
Finished request 2

In my project case, each requests needed to be launch is the right order. If this could help someone :

在我的项目中,需要启动的每个请求都是正确的顺序。如果这能帮助某人:

public class RequestItem: NSObject {
    public var urlToCall: String = ""
    public var method: HTTPMethod = .get
    public var params: [String: String] = [:]
    public var headers: [String: String] = [:]
}


public func trySendRequestsNotSent (trySendRequestsNotSentCompletionHandler: @escaping ([Error]) -> () = { _ in }) {

    // If there is requests
    if !requestItemsToSend.isEmpty {
        let requestItemsToSendCopy = requestItemsToSend

        NSLog("Send list started")
        launchRequestsInOrder(requestItemsToSendCopy, 0, [], launchRequestsInOrderCompletionBlock: { index, errors in
            trySendRequestsNotSentCompletionHandler(errors)
        })
    }
    else {
        trySendRequestsNotSentCompletionHandler([])
    }
}

private func launchRequestsInOrder (_ requestItemsToSend: [RequestItem], _ index: Int, _ errors: [Error], launchRequestsInOrderCompletionBlock: @escaping (_ index: Int, _ errors: [Error] ) -> Void) {

    executeRequest(requestItemsToSend, index, errors, executeRequestCompletionBlock: { currentIndex, errors in
        if currentIndex < requestItemsToSend.count {
            // We didn't reach last request, launch next request
            self.launchRequestsInOrder(requestItemsToSend, currentIndex, errors, launchRequestsInOrderCompletionBlock: { index, errors in

                launchRequestsInOrderCompletionBlock(currentIndex, errors)
            })
        }
        else {
            // We parse and send all requests
            NSLog("Send list finished")
            launchRequestsInOrderCompletionBlock(currentIndex, errors)
        }
    })
}

private func executeRequest (_ requestItemsToSend: [RequestItem], _ index: Int, _ errors: [Error], executeRequestCompletionBlock: @escaping (_ index: Int, _ errors: [Error]) -> Void) {
    NSLog("Send request %d", index)
    Alamofire.request(requestItemsToSend[index].urlToCall, method: requestItemsToSend[index].method, parameters: requestItemsToSend[index].params, headers: requestItemsToSend[index].headers).responseJSON { response in

        var errors: [Error] = errors
        switch response.result {
        case .success:
            // Request sended successfully, we can remove it from not sended request array
            self.requestItemsToSend.remove(at: index)
            break
        case .failure:
            // Still not send we append arror
            errors.append(response.result.error!)
            break
        }
        NSLog("Receive request %d", index)
        executeRequestCompletionBlock(index+1, errors)
    }
}

Call :

电话:

trySendRequestsNotSent()

Result :

结果:

Send list started
Send request 0
Receive request 0
Send request 1
Receive request 1
Send request 2
Receive request 2
...
Send list finished

See for more infos : Gist

看更多信息:要点