こんにちは、KID.Aです。
今回もiOS 7の新機能を紹介させて頂きます。
今まで通信はNSURLConnectionというクラスがありましたが、
iOS 7からはNSURLSessionというクラスが新たに追加されました。
今更感は否めないですが、これからNSURLSessionでできること実装について説明していきます。
NSURLSessionの説明
まず、NSURLSessionでできるようになった点は2つです
- タスクで管理できるようになっている
- バックグラウンドで使用できる
NSURLSessionは非常に豊富なセットが提供されています。
後に説明しますが、セッションとタスクの概念になります。
この概念により、通信のタスク管理やバックグランド通信を行うことができます。
NSURLSessionの概念として、セッションとタスクを簡単に説明していきます。
- セッションの種類
デフォルトセッション | URLからダウンロードするためセッションです。通常の通信の場合はこれを使用します。 |
エフェメラルセッション | デスクにデータが保存されず、メモリにキャッシュするためのセッションです。 |
バックグラウンドセッション | バックグラウンド通信を使用する場合はこのセッションを利用します。 |
- タスクの種類
データタスク | データの送受信をします。バックグラウンドセッションではサポートされません。 |
ダウンロードタスク | アプリケーションが実行されていないときにデータのダウンロードをサポートします。 |
アップロードタスク | アプリケーションが実行されていないときにデータのアップロードをサポートします。 |
NSURLSessionの実装
それでは実際にNSURLSessionを実装してみます。
今回はテックファームのホームページをNSURLSessionで取得したいと思います。
– UIControllerView.mの追加コード –
- (IBAction)pushConnection:(id)sender { // セッションの種類を決めます NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration]; // セッションを作ります NSURLSession *urlSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]]; // データタスクを作成して実行します [[urlSeession dataTaskWithURL: [NSURL URLWithString: @"http://www.techfirm.co.jp/"] completionHandler:^(NSData *data, NSURLResponse *response,NSError *error) { NSLog(@"Got response %@ with error %@.\n", response, error); NSLog(@"DATA:\n%@\nEND DATA\n",[[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]); }] resume]; }
ソースを説明すると、まずNSURLSessionConfigurationでセッションの種類を決めます。
[NSURLSessionConfiguration defaultSessionConfiguration]でデフォルトセッションを作成しています。
urlSessionは実際に作られたNSURLSessionになります。
このNSURLSessionを使用してデータタスクを作成している箇所が「urlSession dataTaskWithURL: completionHandler:」になります。dataTaskWithURLの他にdownloadTaskWithURL、uploadTaskWithRequestなどが用意されており、それらを使えばダウンロードタスクやアップロードタスクを作成することができます。
NSURLSessionの詳細な説明は開発サイトにも記載されています。
https://developer.apple.com/library/ios/documentation/cocoa/Conceptual/URLLoadingSystem/Articles/UsingNSURLSession.html
ここまでがNSURLSessionの説明になります。
バックグラウンド通信の実装
それではいよいよ、タイトルのNSURLSessionでバックグラウンド通信をする実装していきます。
今回は「Background fetch」モードで実行している際にバックグラウンドで画像のダウンロード通信を行ってみます。
「Background fetch」モードの詳しい実装方法は「[iOS 7] Background Fetchについて」で紹介していますのでそちらをご覧ください。
実装
1. MyDownloadDelegateを作成する
ダウンロードタスクを使用する場合はNSURLSessionDownloadDelegateで結果を受け付けるクラスを作成します。
バックグラウンドのハンドリングはNSURLSessionDownloadDelegateの他に、AppDelegateでhandleEventsForBackgroundURLSessionを実装するやり方もあります。今回はNSURLSessionDownloadDelegateを使用するやり方です。
まずはNSURLSessionDownloadTaskを継承したMyDownloadDelegateを作成します。
– MyDownloadDelegate.hのコード –
#import "Foundation/Foundation.h" @interface MyDownloadDelegate : NSObject - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes; - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite; - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location; @end
– MyDownloadDelegate.mのコード –
#import "MyDownloadDelegate.h" @implementation MyDownloadDelegate -(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location { NSLog(@"Session %@ download task %@ finished downloading to URL %@\n", session, downloadTask, location); } -(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { } -(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes { } @end
2. Background fetchの実行時にNSURLSessionを実装する
Background fetchで実行されたバックグラウンド処理はperformFetchWithCompletionHandlerにきます。
その中でバックグランドセッションのダウンロードタスクを実行しています。
– AppDelegate.mの追加コード –
#import "DownLoadTask.h" -(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { // セッションの種類を決めます NSURLSessionConfiguration *backgroundConfigObject = [NSURLSessionConfiguration backgroundSessionConfiguration: @"myBackgroundSessionIdentifier"]; // ダウンロード用のデリゲートを作成します MyDownloadDelegate *downloadDelegate = [[MyDownloadDelegate alloc] init]; // セッションを作ります NSURLSession *urlSession = [NSURLSession sessionWithConfiguration: backgroundConfigObject delegate: downloadDelegate delegateQueue: [NSOperationQueue mainQueue]]; // ダウンロードタスクを作成して実行します [[urlSession downloadTaskWithURL: [NSURL URLWithString: @"http://www.techfirm.co.jp/"]] resume]; completionHandler(UIBackgroundFetchResultNoData); }
これで実装は完了です。
実行結果
以下は実行結果でMyDownloadDelegateのdidFinishDownloadingToURLに出しているログになります。
Session <__NSCFURLSession: 0x9899000> download task <__NSCFBackgroundDownloadTask: 0x98a8360> finished downloading to URL file:///Users/Techfirm/Library/Application%20Support/iPhone%20Simulator/7.0.3-64/Applications/422126C6-C37C-4D4B-A563-B08F5ADC45C4/Library/Caches/com.apple.nsnetworkd/CFNetworkDownload_edGMz3.tmp
となり、tmpファイルがダウンロードされています。
以上がNSURLSessionでバックグラウンド通信で行う実装になります。
NSURLSessionはとても便利なクラスで豊富なメソッドが多く、キャッシュ実装やタスク管理など、
通常だと実装が必要な箇所が予め用意されていますので、それらを有効活用していきましょう。
ピンバック: iOSプログラミングのキモ(iOS7から使えるようになったマルチタスク機能、NSURLSessionはこう使え!)