前提
NSURLSession を利用して NSURLSessionTask を実行します。セッションとタスクのコールバックはブロックではなくデリゲートで受けるものとします。
NSURLSession *URLSession = [NSURLSession sessionWithConfiguration:config delegate:delegate delegateQueue:queue];
NSURLSessionDataTask *task = [URLSession dataTaskWithRequest:request];
[task resume];
このタスクは頻繁にキャンセルされ得るもので、例によりタスクの「成功」「失敗」「キャンセル」を区別したいところです。
[task cancel];
NSURLSessionTaskDelegate
次のデリゲートメソッドでタスクが終了したことを知ることができますが、ここで問題になるのが「成功」「失敗」「キャンセル」の区別の仕方です。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error;
NSURLSessionTaskState には頼れない
タスクの状態を判定する方法もありますが、例のデリゲートメソッドに来た時点ではもう NSURLSessionTaskStateCompleted
になってしまっています。失敗しても completed だということです。これでは使えませんね。
- NSURLSessionTaskStateRunning
- NSURLSessionTaskStateSuspended
- NSURLSessionTaskStateCanceling
- NSURLSessionTaskStateCompleted
タスクの終了の理由をエラーコードで区別する
いずれにしても例のデリゲートメソッドは実行されてしまうので、タスクの終了の理由はエラーの有無とエラーコードで判定します。キャンセルの場合は次のエラーコードが返却されます。
NSURLErrorCancelled
実際にキャンセル時のエラーをダンプしてみると、-999
で一致していることが確認できました。キャンセル時にはこの共通のエラーコード NSURLErrorCancelled
が指定されるということですね。
NSURLErrorCancelled = -999
Error Domain=NSURLErrorDomain Code=-999 "cancelled"
AFNetworking コミュニティの議論
こちらでも NSURLErrorCancelled での判定を推奨しておりました。
Best practice for cancelled errors with AFURLSessionManager
https://github.com/AFNetworking/AFNetworking/issues/1942