关于AFNetworking内存泄漏的解决方案

前言

相信不少喜欢对内存进行优化的开发者都注意到了,使用AFNetworking会造成内存泄漏,当然造成内存泄漏的大部分都是这样使用AFNetworking的:

 // 创建manager对象
    AFHTTPSessionManager   * manager = [AFHTTPSessionManager manager];
 // 发起请求
    [manager POST:@"http://www.host.com" parameters:@{} progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {   
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {     
}];

上面的使用方法很简单,而且也正是AFNetworking推荐我们这样使用的。从上面的代码使用看,我们自己造成内存泄漏问题的概率几乎为0,既然不是我们的问题,那么就是AFNetworking自己的问题。但是你会郁闷,为什么AFNetworking这么出名的一个第三方网络框架,会有这个问题呢?

问题所在

通过翻阅AFNetworking的源码,我找出了具体的原因,如下图:

图1.png

我们使用的manager对自己内部创建的session有一个强引用,然而manager自身作为NSURLSession的代理,也传给了session,然后这个session为了确保网络数据的正常使用,会对manager也进行一个强引用。因此,这里其实有一个循环引用。

苹果的api文档也告诉我们了,如下图:

图2.png

解决问题

既然问题找到了,那么就来解决它。

方案1:

现在为止,网上搜到的解决方案:既然是我们创建的manager内存泄漏了,那么很好办,我们就干脆把这个manager弄成一个单例,每次发起请求的时候,就用这个单例manager进行网络请求。因为AFNetworking内部支持发起多个任务,所以使用起来也完全没有问题。

但是我个人认为,这样做其实不太好。参考图一,我们知道网络请求回来的代理回调都是在一个串行队列里执行的。既然是串行队列,那执行任务肯定都是一个一个按照先后顺序来的。如果我们同时发起了4个下载任务(发起的请求是异步的),数据代理回调却是同步的。在效率上肯定是有点影响的

方案2:

这是我自己写的解决方案(其实图2,苹果的文档已经告诉我们了)

AFHTTPSessionManager   * hhmanager = [AFHTTPSessionManager manager];

NSURLSession    * managerSession = hhmanager.session;
[hhmanager POST:@"http://www.host.com" parameters:@{} progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
    // 做你自己的处理
    
    // 在最后的时候执行下面代码
    [managerSession finishTasksAndInvalidate];
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
    // 做你自己的处理
    
    // 在最后的时候执行下面代码
    [managerSession finishTasksAndInvalidate];
}];

在网络请求完成的时候,使对应的session无效,这样就打破了之前我们提到的循环引用,使得manager被释放。

你可能感兴趣的:(关于AFNetworking内存泄漏的解决方案)