Quantcast
Channel: Nelson 寫些 iOS 開發的東東
Viewing all articles
Browse latest Browse all 20

一個 AFNetworking 的 retain cycle 問題

$
0
0

AFNetworking封裝了網路連線的許多工作,讓 iOS/Mac 開發者可以用簡潔的寫法去處理連線,但你知道要如何正確使用,才不會出現 retain cycle 嗎?

舉個例子

舉個最簡單的例子,我們可能會在自訂的 UIViewController 裡頭建立一個 AFHTTPSessionManager,透過它來進行網路連線,大部分的寫法大概如下:

@interface MyViewController ()
@property (nonatomic, strong) AFHTTPSessionManager *manager;
@end

@implementation MyViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.manager = [AFHTTPSessionManager manager];
    // Do something with self.manager...
}
@end

簡單直覺,對吧?但是你會發現在 view controller 被摧毀之後,這個 AFHTTPSessionManager還存留在記憶體裡面,不信的話可以用 Xcode 的 Memory Graph 檢查看看。

你不信邪,所以你可能會試著在 dealloc把它設為 nil,這樣總該沒問題了吧?

- (void)dealloc {
    _manager = nil;
}

可惜的是,這樣做沒有用,它依然存在記憶體裡。怎!麽!可!能!原因在一開始就提到了,因為它有 retain cycle。正確釋放的做法如下,你需要先呼叫 invalidateSessionCancelingTasks:這個函式:

- (void)dealloc {
    [_manager invalidateSessionCancelingTasks:YES];
    _manager = nil;
}

為什麼會這樣

因為 AFHTTPSessionManager擁有一個 NSURLSession *session property,而且把這個 session 的 delegate設為 self,而 NSURLSessiondelegate設為 retain。所以它們互相擁有彼此,造成了 retain cycle。

當我們呼叫 invalidateSessionCancelingTasks:函式,它會去呼叫 NSURLSessioninvalidateAndCancelfinishTasksAndInvalidate。根據蘋果文件,呼叫這兩個函式之後,NSURLSession才會斷開它與 delegate 的關聯。至此,才打破 retain cycle。

解法

有兩個解法,第一個就是如上所述,記得最後要呼叫 invalidateSessionCancelingTasks:來結束任務。第二個就是把 AFHTTPSessionManager寫成 singleton,這樣有 retain cycle 也無所謂了。


Viewing all articles
Browse latest Browse all 20