[英]Cancel DispatchWorkItem outside loop - Swift
我一直在使用DispatchWorkItem
和DispatchQueue
在我的应用程序中发出异步请求。 但是,我在尝试中止其中一个请求时遇到了麻烦。
我成功地使用workItem.cancel()
来更改标志,然后在我想中止的地方检查它。 像这样:
for stop in self.userSettingsController.history {
stop.PassingInfo?.removeAll()
if workItem?.isCancelled ?? false {
print("CANCELED")
workItem = nil
break
}
...
但是,在一种情况下,我没有循环可以继续检查cancelled
标志是否更改,因此我无法使用上述过程中止请求。 这是代码:
let tripQueue = DispatchQueue(label: "tripQueue")
var tripWorkItem: DispatchWorkItem? = nil
tripWorkItem = DispatchWorkItem {
self.soapServices.GetPathsByLineAndDirection(lineCode: self.lineCode!, direction: passingInfo.Direction!) { response in
DispatchQueue.main.async {
self.linePaths = response?.filter({$0.Places.contains(where: {$0.Code == self.singleStopSelected?.Code})})
if realTime {
//Get estimated trip
self.showingRealTime = true
if self.linePaths?.count ?? 0 > 0 {
self.getEstimatedTrip(lineCode: self.lineCode ?? "", direction: passingInfo.Direction ?? 0, stopCode: self.singleStopSelected?.Code ?? "", path: (self.linePaths?.first)!) { updateTripTimes in
//Does not work, as is expected. Just showing what I would like to achieve
if tripWorkItem?.isCancelled ?? false {
tripWorkItem = nil
return
}
if updateTripTimes {
DispatchQueue.main.async {
self.updateTripTimes = true
}
}
}
}
} else {
//Get trip
self.showingRealTime = false
self.getTrip(tripId: passingInfo.Id!)
}
}
}
tripWorkItem = nil
}
self.currentTripWorkItem = tripWorkItem
tripQueue.async(execute: tripWorkItem ?? DispatchWorkItem {})
有没有办法做到这一点?
提前致谢。
ps:如果这是重复的,我很抱歉,但我之前搜索过,但找不到问题。 我可能使用了错误的术语。
与其将代码放在DispatchWorkItem
,不如考虑将其包装在Operation
子类中。 你得到相同的isCancelled
布尔模式:
class ComputeOperation: Operation {
override func main() {
while ... {
if isCancelled { break }
// do iteration of the calculation
}
// all done
}
}
为了您的网络请求,将它包装在一个自定义的AsynchronousOperation
子类(如这个实现),并实现cancel
,将取消获得的网络请求。 例如:
enum NetworkOperationError: Error {
case unknownError(Data?, URLResponse?)
}
class NetworkOperation: AsynchronousOperation {
var task: URLSessionTask!
init(url: URL, completion: @escaping (Result<Data, Error>) -> Void) {
super.init()
self.task = URLSession.shared.dataTask(with: url) { data, response, error in
guard
let responseData = data,
let httpResponse = response as? HTTPURLResponse,
200 ..< 300 ~= httpResponse.statusCode,
error == nil
else {
DispatchQueue.main.async {
completion(.failure(error ?? NetworkOperationError.unknownError(data, response)))
self.finish()
}
return
}
DispatchQueue.main.async {
completion(.success(responseData))
self.finish()
}
}
}
override func main() {
task.resume()
}
override func cancel() {
super.cancel()
task.cancel()
}
}
不要迷失在上面例子的细节中。 请注意
AsynchronousOperation
;finish
调用完成处理后; 和cancel
实现取消异步任务。然后你可以定义你的队列:
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 4 // use whatever you think is reasonable
并将您的操作添加到其中:
let operation = NetworkOperation(url: url) { response in
switch response {
case .failure(let error):
// do something with `error`
case .success(let data):
// do something with `data`
}
}
queue.addOperation(operation)
现在,您的GetPathsByLineAndDirection
和getEstimatedTrip
的问题是您没有遵循“可取消”模式,即您似乎没有返回任何可用于取消请求的内容。
所以,让我们看一个例子。 想象一下,您有一些简单的方法,例如:
func startNetworkRequest(with url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> Void) {
let task = URLSession.shared.dataTask(with: url) { data, response, error in
completion(data, response, error)
}
task.resume()
}
您要做的是将其更改为返回可以取消的内容,即本示例中的URLSessionTask
:
@discardableResult
func startNetworkRequest(with url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> Void) -> URLSessionTask {
let task = URLSession.shared.dataTask(with: url) { data, response, error in
completion(data, response, error)
}
task.resume()
return task
}
现在这是一个可取消的异步任务(你可以用上面的AsynchronousOperation
模式包装它)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.