【问题标题】:Waiting for request to finish before executing the next operation在执行下一个操作之前等待请求完成
【发布时间】:2017-02-15 09:10:43
【问题描述】:

我想知道如何等待发送请求的操作完成上传(并获得响应),然后再执行另一段代码。我试图用 NSOperations 来做到这一点:

    let testOp = BlockOperation {
        var result = 0

        for i in 1...1000000000 {
            result += i
        }
    }

    let logOp = BlockOperation {
        self.debug.log(tag: "test", content: "testing")
    }

    logOp.completionBlock = {
        print("------- logOp completed")
    }

    logOp.addDependency(testOp)

    let sendOp = BlockOperation {
        self.debug.sendLog() //uploads log, using URLSession.shared.dataTask
    }

    sendOp.completionBlock = {
        print("------- sendOp completed")
    }

    sendOp.addDependency(logOp)

    let emptyOp = BlockOperation {
        self.debug.empty()
    }

    emptyOp.completionBlock = {
        print("------- emptyOp completed")
    }

    emptyOp.addDependency(sendOp)

    let queue = OperationQueue()
    queue.addOperations([testOp, logOp, sendOp, emptyOp], waitUntilFinished: false)

输出:

------- logOp completed
*** Sending debug log (coming from self.debug.sendLog())
------- sendOp completed
------- emptyOp completed
*** sendLog uploaded (coming from self.debug.sendLog())

根据我的代码,我预计输出是:

------- logOp completed
*** Sending debug log
*** sendLog uploaded
------- sendOp completed
------- emptyOp completed

我是怎么做到的?我可以用 NSOperations 做到这一点吗?

关于 debug.sendLog() 函数的更多细节:

func sendLog() {
    ...
    var urlRequest = URLRequest(url: url!)
    urlRequest.httpMethod = "POST"
    ...

    let session = URLSession.shared
    let task = session.dataTask(with: urlRequest, completionHandler: {
        (data, response, error) in

        ...

        DispatchQueue.main.async {
            print("*** sendLog uploaded")

        }
    })

    task.resume()
}

【问题讨论】:

  • “根据我的代码,我预计输出是......”。需要明确的是,这种期望是错误的。 print("*** sendLog uploaded")主队列 上异步运行,而 NSOperationQueue 默认为 全局并发默认(优先级)调度队列
  • 我调整了我的代码以完全删除 DispatchQueue.main.async 块。这似乎不会改变结果。我可以通过使用信号量让请求等待,但这感觉很糟糕。我看不出 NSoperations 有什么用处。当然,您可以获得状态,并轻松取消一大堆操作,但如果您的代码结构良好,您甚至不应该走到需要取消的那一步。
  • 没错,另一个问题是dataTask已经与task.resume()异步执行。您可能需要另一个可以处理异步“回调”/“未来”/“承诺”方式的概念,或者 - 为简单起见 - 您提到的 a synchronous request 或其他机制。信号量变体可能看起来/感觉很老套,但它是一个简短且可维护的解决方案,只要您注意不要过度使用它并且不阻塞主队列就可以了。
  • 这是一个关于主题的nice and well commented StackOverflow Entry,objective-c 代码思想。这应该使 NSURLSession 任务保持一致并使取消成为可能。
  • @makadev 感谢 cmets 和链接。这很有帮助。

标签: ios swift swift2


【解决方案1】:

您可以将完成块直接添加到 sendLog 方法中,并放弃所有块操作的东西。

func sendLog(withCompletion completion: (() -> Void)) {
    ...
    var urlRequest = URLRequest(url: url!)
    urlRequest.httpMethod = "POST"
    ...

    let session = URLSession.shared
    let task = session.dataTask(with: urlRequest, completionHandler: {
        (data, response, error) in

        ...
        completion?()
    })

    task.resume()
}

然后像这样调用你的sendLog 方法:

sendLog(withCompletion: {
   // Execute the code you want to happen on completion here.
})

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-31
    • 1970-01-01
    • 2019-02-11
    • 1970-01-01
    相关资源
    最近更新 更多