instrument檢測AFNetworking工具類記憶體洩露及解決方案
最近這段時間研究了一下記憶體相關的知識,正好對專案程式碼做一下優化,檢測後還是發現了一些問題,這裡主要講一下之前遺留的程式碼中對AFN封裝的工具類中存在較嚴重的記憶體洩露問題.

螢幕快照 2018-09-20 下午5.02.41.png

螢幕快照 2018-09-20 下午5.03.18.png

螢幕快照 2018-09-20 下午5.04.16.png
經過排查之後定位到封裝的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原始碼:

螢幕快照 2018-09-20 下午5.31.14.png
這裡的類方法manger每次呼叫就會建立物件並返回,繼續深入檢視原始碼,最終發現問題, 定位到如下位置:

螢幕快照 2018-09-20 下午5.35.20.png
問題就出現在這個方法裡面呼叫的代理方法,繼續點選呼叫delegate方法,發現蘋果的NSURLSession類中的代理是用retain修飾,使用的是強引用,如圖:

螢幕快照 2018-09-20 下午5.01.01.png

螢幕快照 2018-09-20 下午5.00.30.png
這裡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呼叫不當導致的記憶體問題