一个编写iOS代码的经典场景:用户进入某个Controller,发起Http网络请求从Server获取数据,在数据返回之前用户退出了Controller。此时是否需要Cancel之前发出的网络请求呢?
如果请求的数据只在当前Controller产生内容,结论当然是需要Cancel,虽然我知道不少iOS程序员因为偷懒而忘了取消。我们用工程的思维,深入本质,一起看下这背后都发生了什么,如果不Cancel会有哪些副作用。
我们可以把一个Http请求分为这几步:
第一步:三次握手这一步会有三个packet产生,sync,sync+ack,ack。
第二步:客户端发送Http的request此处根据请求类型产生的packet数量会有差异。
第三步:客户端接收Server的Http Response根据Response的大小,产生的packet数量不相同,一般一个packet在1.5KB左右。
如果我们在请求返回之前,调用Cancel:
取消请求的话,客户端会发送如下一个Reset Packet断开当前的Http连接,阻止后续的流量产生:
所以结论是:如果不Cancel,请求完成之后通过回调找到delegate,如果是weak引用,Controller被释放,delegate变为nil,业务流程被中断,代码还算安全。但是会的的确确浪费一些用户流量。养成好习惯,自己产生的垃圾自己清理哦。
我的总结:
第一点:控制器已经被销毁了,但是请求还在继续。controller虽然销毁了,但是网络请求是另一个对象(比如说AFN对象)发起的,这个AFN对象还没有销毁,所以网络还在继续。
第二点:不管当前该网络请求成功或者失败,都会回到当初发起网络请求的block里面。而这个块是在销毁控制器里。
假如代码如下:摘自http://casatwy.com/
__weak typeof(self) weakSelf = self; \
REQUEST_ID = [[CTApiProxy sharedInstance] call##REQUEST_METHOD##WithParams:apiParams serviceIdentifier:self.child.serviceType methodName:self.child.methodName success:^(CTURLResponse *response) { \
__strong typeof(weakSelf) strongSelf = weakSelf; \
[strongSelf successedOnCallingAPI:response]; \
} fail:^(CTURLResponse *response) { \
__strong typeof(weakSelf) strongSelf = weakSelf; \
[strongSelf failedOnCallingAPI:response withErrorType:CTAPIManagerErrorTypeDefault]; \
}]; \
[self.requestIdList addObject:@(REQUEST_ID)]; \
第三点:以上代码,
__weak typeof(self) weakSelf = self;
因为weak引用,Controller被释放,strongSelf被置为nil, 业务流程被中断.
第四点:
【task cancel】把网络请求cancel掉,仍然会走回调,不过是会回调到error的那个block里面,通过打印NSError的信息,可以看出有个cancelled的字段,说明当前网络失败的原因是因为取消网络请求导致的