【问题标题】:How to do two concurrent API calls in swift 4如何在 swift 4 中进行两个并发 API 调用
【发布时间】:2018-11-06 12:28:26
【问题描述】:

提前感谢您的帮助, 我有两个 API 调用,都是并发的,任何调用都可能首先成功(我不想按顺序调用),在两个调用成功后,我必须停止我的活动指示器并重新加载我的 tableView, 这是我的代码,但我不知道这是否正确,以及如何重新加载我的 tableView 并停止我的活动指示器。

func downloadDetails(){
    let operationQueue: OperationQueue = OperationQueue()
    let operation1 = BlockOperation() {
    WebServiceManager.getAData(format:A, withCompletion: {(data: Any? , error: Error?) -> Void in

          if let success = data {
              DispatchQueue.main.async {
                  (success code)
              }
           }
        })

        let operation2 = BlockOperation() {
        webServiceManager.getBData(format: B, withCompletion: {(data: Any? , error: Error?) -> Void in

                if let success = data {
                    DispatchQueue.main.async {
                       (success code)
                    }
                }
            })
        }
        operationQueue.addOperation(operation2)
    }
    operationQueue.addOperation(operation1)
}
downloadDetails() "calling function"

【问题讨论】:

    标签: ios swift4 nsoperationqueue nsoperation swift4.1


    【解决方案1】:

    我会使用 OperationQueue。

    它是长时间运行的任务的首选,如果需要,您可以控制取消请求。

    在每个操作结束时,您可以检查操作计数以了解剩余操作。

    我添加了伪代码。

    let operationQueue: OperationQueue = OperationQueue()
    
    func downloadDetails(){
    
        let operation1 = BlockOperation() { [weak self] in
    
            guard let strongSelf = self else {
                return
            }
    
            sleep(2)
    
            DispatchQueue.main.async {
                strongSelf.handleResponse()
            }
    
            let operation2 = BlockOperation() { [weak self] in
    
                guard let strongSelf = self else {
                    return
                }
    
                sleep(2)
    
                DispatchQueue.main.async {
                    strongSelf.handleResponse()
                }
            }
            strongSelf.operationQueue.addOperation(operation2)
        }
    
        self.operationQueue.addOperation(operation1)
    }
    
    func handleResponse() {
        print("OPERATIONS IN PROGRESS: \(self.operationQueue.operations.count)")
        if self.operationQueue.operations.count == 0 {
            print("ALL OPERATIONS ARE COMPLETE")
        }
    }
    
    func cancelOperation() {
        self.operationQueue.cancelAllOperations()
    }
    

    打印出来

    OPERATIONS IN PROGRESS: 1
    OPERATIONS IN PROGRESS: 0
    ALL OPERATIONS ARE COMPLETE
    

    【讨论】:

    • 非常感谢 kthorat 的快速回复。但我想知道如何在这里触发这个 cancelOperation()?
    • 如果您不再需要它,您应该取消请求。例如,如果您在屏幕上开始请求,您应该在用户离开屏幕后取消。所以 ViewWillAppear 正在发出请求,然后您可以在 ViewWillDisappear 上取消。有意义吗?
    • @k-thorat 如果我想依次调用两个或多个 API 怎么办?
    【解决方案2】:

    这正是DispatchGroup 的用例。为每个呼叫输入组,在呼叫结束时离开组,并添加一个通知处理程序以在它们全部完成时触发。不需要单独的操作队列;这些已经是异步操作了。

    func downloadDetails(){
        let dispatchGroup = DispatchGroup()
    
        dispatchGroup.enter()   // <<---
        WebServiceManager.getAData(format:A, withCompletion: {(data: Any? , error: Error?) -> Void in
    
            if let success = data {
    
                DispatchQueue.main.async {
                    (success code)
                    dispatchGroup.leave()   // <<----
                }
            }
        })
    
        dispatchGroup.enter()   // <<---
        webServiceManager.getBData(format: B, withCompletion: {(data: Any? , error: Error?) -> Void in
    
            if let success = data {
    
                DispatchQueue.main.async {
                   (success code)
                   dispatchGroup.leave()   // <<----
                }
            }
        })
    
        dispatchGroup.notify(queue: .main) {
            // whatever you want to do when both are done
        }
    }
    

    【讨论】:

    • 如果调用失败了怎么办?我也可以在错误块中使用 dispatchGroup.leave() 吗?
    • 是的。无论成功还是失败,您都必须为每个enter() 调用一次leave()
    • @RobNapier 上次我使用 dispatchGroup 时无法取消请求。这仍然是真的,对吧?
    • 按照你的意思,答案是肯定的,但这不是一个好的思考方式。每次进入时,您必须只离开一次。您完全可以取消操作;但是您仍然需要离开该组。 (我知道这是迂腐的;但重要的是要考虑组的实际作用。)如果你的意思是你不能避免运行通知块,那是真的。无法取消订阅群组完成。如果你想要这种取消,你可以向上移动一层到操作,但我发现它们对于大多数问题来说太复杂了。
    • 知道了。非常感谢@RobNapier
    猜你喜欢
    • 1970-01-01
    • 2018-09-26
    • 1970-01-01
    • 2021-09-20
    • 2021-06-29
    • 2017-07-10
    • 2014-08-10
    • 2022-06-10
    • 1970-01-01
    相关资源
    最近更新 更多