最近這段時(shí)間研究了一下內(nèi)存相關(guān)的知識,正好對項(xiàng)目代碼做一下優(yōu)化,檢測后還是發(fā)現(xiàn)了一些問題,這里主要講一下之前遺留的代碼中對AFN封裝的工具類中存在較嚴(yán)重的內(nèi)存泄露問題.



經(jīng)過排查之后定位到封裝的AFN工具類內(nèi)部的manger,項(xiàng)目中的代碼如下:
- (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;
估計(jì)也有一部分人使用上面的這種方式封裝一個(gè)基礎(chǔ)的對象方法進(jìn)行一些網(wǎng)絡(luò)配置,然后在GET和POST方法里面調(diào)用,但這會(huì)導(dǎo)致你會(huì)反復(fù)的調(diào)用 AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]方法;問題就出在這里, 點(diǎn)擊查看AFN源碼:

這里的類方法manger每次調(diào)用就會(huì)創(chuàng)建對象并返回,繼續(xù)深入查看源碼,最終發(fā)現(xiàn)問題, 定位到如下位置:

問題就出現(xiàn)在這個(gè)方法里面調(diào)用的代理方法,繼續(xù)點(diǎn)擊調(diào)用delegate方法,發(fā)現(xiàn)蘋果的NSURLSession類中的代理是用retain修飾,使用的是強(qiáng)引用,如圖:


這里delegate是使用強(qiáng)引用持有,而self.session本身也是使用strong修飾的強(qiáng)引用類型,這就明顯造成了循環(huán)引用: self.session.delegate = self ; self持有session,session持有delegate,而delegate又持有self
解決方法:
封裝AFHTTPSessionManager單例對象,編譯初始化單例類,一直保持在內(nèi)存中,直至APP退出后由系統(tǒng)釋放這部分內(nèi)存; 這樣每次調(diào)用單例對象就避免了循環(huán)引用造成的內(nèi)存泄露:
#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
經(jīng)過leaks再次檢測, 已順利解決了因manger調(diào)用不當(dāng)導(dǎo)致的內(nèi)存問題