前回、前々回とNSURLSessionを取り扱ってきた。

[iOS] NSURLSessionを使って通信を行う
[iOS] NSURLSessionでマルチパートデータを送信する

NSURLSessionはとても便利だが、しっかりとセッションの後処理をしないとメモリリークが発生するようだ。
公式ドキュメントにこのように書いてある。
NSURLSession Class Reference

The session object keeps a strong reference to the delegate until your app explicitly invalidates the session. If you do not invalidate the session by calling the invalidateAndCancel orresetWithCompletionHandler: method, your app leaks memory.

要はセッションはデリゲートを強参照するため、手動で終了処理を行わないといけないようだ。

本当にメモリリークするかLeaksで見てみた。
NSURLSessionメモリリーク_ss1
何度か連続してセッションを実行させていると確かにメモリリークが発生している。
そこで、デリゲートメソッドでセッションの後始末をするようにしてみる。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    [session invalidateAndCancel];
}
結果はこうだ。
NSURLSessionメモリリーク_ss2
メモリリークは起きなくなった。
これで解決だ。

では、デリゲートを使わない場合はどうだろう。
    NSURLSessionDataTask* task =
        [session dataTaskWithURL:url
           completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
           }];
このようにcompletionHandlerを指定する場合だ。

実行してみると、この場合でもメモリリークが起きた。
なので、この場合でもこのようにしっかりと後始末をした方が良いだろう。
    NSURLSessionDataTask* task =
        [session dataTaskWithURL:url
           completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
               [session invalidateAndCancel];
           }];