AFN的記憶體洩漏問題

Nil_Lu發表於2017-12-01

在使用instruments做記憶體洩漏分析時,發現所有使用如下語句的地方都有記憶體洩漏,OMG:

leaks上圖:

AFN的記憶體洩漏問題

if (!_manager) {
    _manager = [AFHTTPSessionManager manager];
}
複製程式碼

原因:session在ARC下不會及時釋放

我所用到的網路請求不是很複雜,不想再新建類去寫單例了,就把單例放在了AppDelegate中,用到的時候在通過AppDelegate拿。因為需要用到AFURLSessionManager,所以就寫一個單例方法。

static AFHTTPSessionManager *manager ;`
-(AFHTTPSessionManager *)sharedHTTPSession{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [AFHTTPSessionManager manager];
        manager.requestSerializer.timeoutInterval = 10;
    });
    return manager;
}
複製程式碼

但是 做成單例並不是很好的方式,可以在AFAppDotNetAPIClient中的dealloc中手動觸發sessionManager.session.finish...()釋放session的delegete,打破AF內部的迴圈引用

完美解決 @·@
原因探究: AFURLSessionManager實現了NSURLSession的協議,即AFURLSessionManagerNSURLSession互相持有,如果這個delegate是week的話,那沒什麼問題,但是系統提供的是retain:如圖

NSURLSession

所以裡面是有迴圈引用的。一旦使用非單例的方式來使用AFHTTPSessionManager,如果不做特殊處理,就會導致這個物件在應用存活期間是不會銷燬的,如果應用網路請求過多,使用者反覆進入各種vc,記憶體洩漏明顯。這明顯不安全。

好在AFN和NSURLSession都有方法可以解決:

//廢棄session物件。cancelPendingTasks決定是否取消此session中的tasks
–(void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks 
複製程式碼

方法二:

__weak typeof(manager) weak_manager = manager;
    [manager requestWithMethod:method
        URLString:uri
        parameters:param
        success:^(NSURLSessionDataTask *task, id responseObject) {
            if (completion) {
                completion(YES, responseObject, task.response);
            }
            [weak_manager invalidateSessionCancelingTasks:YES];
        }
        failure:^(NSURLSessionDataTask *task, NSError *error) {
            if (completion) {
                completion(NO, error, task.response);
            }
            [weak_manager invalidateSessionCancelingTasks:YES];
        }];
複製程式碼

相關文章