iOS 7で一新された通信周り〜NSURLSessionってなに?〜

iOS 7 API

NSURLSessionってなに?

iOS 7,OS X 10.9からNSURLSessionなるクラスが追加されました。NSURLSessionとは何か?それはズバリNSURLConnectionクラスに取って代わる、より使いやすくなったNSURLConnectionの強化版といったところでしょうか。NSURLSessionを利用するメリットは次の2つがあります。

  • 今までNSURLConnectionより簡単・便利
  • バックグラウンドでダウンロード・アップロード処理が行える(!)

本記事ではこの新しく便利なクラスNSURLSessionについて解説していきたいと思います。

NSURLConnectionの復習

まずNSURLSessionの説明を始める前に、NSURLConnectionのできることを復習をしましょう。
NSURLConnectionはどんなクラスかと言うと、WebサーバやファイルサーバなどのデータソースからURLを指定してデータを非同期で取得することができるクラスです。このクラスを用いることで通信処理中アプリケーション全体をブロックさせないように通信処理を書くことができます。

NSURLConnectionを用いた非同期通信には、このクラス以外に以下の3つの登場人物が存在します。

  • NSURLRequest
  • NSURLResponse
  • デリゲートオブジェクト

NSURLConnectionを用いて非同期的にデータを取得する場合、まず生成したNSURLRequestインスタンスに対して通信先のURLの他に、タイムアウトやキャッシュ、認証方法などの設定を行います。次にNSURLConnectionはこのNSURLRequestインスタンスとデリゲートオブジェクトを指定してインスタンスの生成と同時にデータの取得を開始します。このとき発生するデータ取得の開始や受信時、そして取得完了といったイベントはデリゲートオブジェクトに実装したデリゲートメソッドで行います。また、アクセス先のデータソースから送られるステータスコードやHTTPヘッダなどのレスポンスはNSURLResponseに設定され、デリゲートメソッドの引数として渡されます。

このように、NSURLConnectionを使用すると比較的簡単に非同期的なデータ取得が行えます。しかし、この方法だと実はデータ取得ごとにこれらの設定をその都度行わなくてはなりません。でもほとんどのアプリではURLが変わってもタイムアウトやキャッシュのポリシー、認証に関する設定は基本的に共通ですよね。
この設定を共通化するために、シングルトンのクラスを用意してNSURLRequestを生成するメソッドを独自に定義したりしていた方もたくさんいらっしゃるかと思います。

この煩わしさを解消するために新たに登場したのがNSURLSessionです!!

なぜNSURLSessionが便利か?

接続に関する設定の共通化が簡単にできる

と前置きが長くなってしまいましたが、ようやくNSURLSessionの登場です。なぜ、NSURLConnectionよりNSURLSessionの方が便利なのでしょうか?たくさん要因はありますが、まず最初に思いつくこと、それはタイムアウトやキャッシュのポリシー、認証に関する設定を共通化できるよう予め設計されていることです!そのため、今までのように設定の共通化のために自前のシングルトンクラスを準備したりリクエストのサブクラスを作成する手間が省けるわけです。

AFNetworkingみたいな記述が標準でもできる

NSURLConnectionを使う方法だと、標準ではDelegate用のクラスやメソッドを用意しなければなりません。サードパーティ製のライブラリであるAFNetworkingを使用すれば成功・失敗のコールバックにブロックが使用できますよね。このAFNetworkingみたいな記述が標準でも可能になりました!

バックグラウンドでダウンロード・アップロード処理が行える

何と言ってもこれですよね!NSURLSessionを使えばバックグラウンドでもダウンロード・アップロード処理を行うことができます。しかもOS側でバッテリーの持ち具合とかみて動作してくれるようです。特に、iOS 7より加わったプッシュ通知や定期的なフェッチ処理などと組み合わせて使うことで効果を発揮するようです。

まぁ何より文章を読むよりやはり手を動かした方が頭に入りやすいと思いますので、実際にサンプルコードを見てみましょう。

リプレイス前のソース
// NSURLConnection example:
id<NSURLConnectionDelegate> myDelegate = [[MyDelegate alloc] init];

for (int i = 0; i < 10; i++) {
    NSURL* myURL = [NSURL URLWithString:@”http://www.apple.com/”];
    NSURLRequest* myRequest = [NSURLRequest requestWithURL:myURL];
    [myRequest setAllowsCellularAccess:NO];
    NSURLConnection* conn;
    conn = [NSURLConnection connectionWithRequest:myRequest
                                         delegate:myDelegate];
}
リプレイス後のソース
// NSURLSession example:
id<NSURLSessionDelegate> myDelegate = [[MyDelegate alloc] init];

NSURLSessionConfiguration* myConfiguration = [NSURLSession defaultSessionConfiguration];
myConfiguration.allowsCellularAccess = NO;

NSURLSession* mySession = [NSURLSession sessionWithConfiguration:myConfiguration
                                                        delegate:myDelegate
                                                   delegateQueue:[NSOperationQueue mainQueue];

for (int i = 0; i < 10; i++) {
    NSURL* myURL = [NSURL URLWithString:@”http://www.apple.com/”];
    NSURLSessionDataTask* task;
    task = [mySession dataTaskWithHTTPGetRequest:myURL];
}

上のソースはアップルのサイトに10回アクセスするだけの簡単なサンプルです。リプレイス前のソースではループ内で都度コネクションとリクエストを生成して設定(ここではallowsCellularAccessをNOに)しています。リプレイス後のソースを見ると、ループの外でNSURLSessionConfigurationインスタンスに対して設定を行うようになっています。

まぁこれだけ見てもありがたみをまだ感じられませんよね。という訳で次回は基本的な使い方としてNSURLSessionでAFNetworkingみたいな実装など書きたいと思います!