最近这段时间研究了一下内存相关的知识,正好对项目代码做一下优化,检测后还是发现了一些问题,这里主要讲一下之前遗留的代码中对AFN封装的工具类中存在较严重的内存泄露问题.
经过排查之后定位到封装的AFN工具类内部的manger,项目中的代码如下:
- (NSURLSessionDataTask *)startOperationWithPath:(NSString *)string params:(NSMutableDictionary *)param success:(AFResponseBlock)success failure:(AFResponseErrorBlock)failure
{
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
AFHTTPRequestSerializer *serializer = [AFHTTPRequestSerializer serializer];
NSURLRequestReturnCacheDataElseLoad
manager.requestSerializer = serializer;
估计也有一部分人使用上面的这种方式封装一个基础的对象方法进行一些网络配置,然后在GET和POST方法里面调用,但这会导致你会反复的调用 AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]方法;问题就出在这里, 点击查看AFN源码:
这里的类方法manger每次调用就会创建对象并返回,继续深入查看源码,最终发现问题, 定位到如下位置:
问题就出现在这个方法里面调用的代理方法,继续点击调用delegate方法,发现苹果的NSURLSession类中的代理是用retain修饰,使用的是强引用,如图:
这里delegate是使用强引用持有,而self.session本身也是使用strong修饰的强引用类型,这就明显造成了循环引用: self.session.delegate = self ; self持有session,session持有delegate,而delegate又持有self
解决方法:
封装AFHTTPSessionManager单例对象,编译初始化单例类,一直保持在内存中,直至APP退出后由系统释放这部分内存; 这样每次调用单例对象就避免了循环引用造成的内存泄露:
#import "HDNetManger.h"
@implementation HDNetManger
+(AFHTTPSessionManager *)shareManger{
static AFHTTPSessionManager *manger = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manger = [AFHTTPSessionManager manager];
});
return manger;
}
@end
经过leaks再次检测, 已顺利解决了因manger调用不当导致的内存问题