【发布时间】: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 和链接。这很有帮助。