通过手动创建又或者第三方框架(AFNetworking、Alamofire)发起一个请求后,一般都会返回一个请求任务,也就是 NSURLSessionDataTask 类型的对象,比如:
let url1 = URL(string: "https://www.qq.com")!
let urlTask = URLSession.shared.dataTask(with: url1) { (data: Data?, resp: URLResponse?, error: Error?) in
print(data as Any, resp as Any, error as Any)
}
urlTask.resume()
如果这个请求由一个控制器发起,比如说查看某个订单的详情,有一个良好的实践时,在页面 pop 出栈 viewWillDisappear: 时取消该请求,比如这样:
override viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if (isLeaving) { // 见下文分析
urlTask.cancel()
}
}
通过日志可以可以看到结论:
在成功或者失败回调进行手动取消的请求,最后会以失败的方式回调
Task <8AC12E49-CC35-4E32-87DC-69457E9210BA>.<1> finished with error - code: -999
(Data) nil
(URLResponse) nil
(Error) Optional(Error Domain=NSURLErrorDomain
Code=-999 "cancelled"
UserInfo={
NSErrorFailingURLStringKey=https://www.qq.com/,
NSLocalizedDescription=cancelled,
NSErrorFailingURLKey=https://www.qq.com/
})
由此可以判断出 Domain 为 NSURLErrorDomain,code = -999 的是手动取消的请求,可以判断做特别的处理。
如何判断控制器是被 pop 出栈呢?
在参考文献《iOS判断UIViewController是被Push还是被Pop或者被Present或Dismiss》中可以从 UIViewController 类中看到如下属性:
@available(iOS 5.0, *)
open var isBeingPresented: Bool { get }
@available(iOS 5.0, *)
open var isBeingDismissed: Bool { get }
@available(iOS 5.0, *)
open var isMovingToParent: Bool { get }
@available(iOS 5.0, *)
open var isMovingFromParent: Bool { get }
其中的注释如下:
These four methods can be used in a view controller's appearance callbacks to determine if it is being
presented, dismissed, or added or removed as a child view controller. For example, a view controller can
check if it is disappearing because it was dismissed or popped by asking itself in its viewWillDisappear:
method by checking the expression ([self isBeingDismissed] || [self isMovingFromParentViewController]).
结合注释可以很轻松地得出结论:
extension UIViewController {
var isLeaving: Bool {
return isBeingDismissed || isMovingFromParentViewController
}
}
网友评论