Web APIの叩き方いろいろ

当初はBaaS系のサービスを比較してみようと思っていましたが、諸事情による急遽内容を変更いたします。

## モバイルアプリには欠かせないWebとの連携

最近のモバイルアプリでは、Web APIからデータを取ってきたり、画像をダウンロードしたりと、Webとの連携が必要な場合が殆どですね。
iOS SDKにはWebとの連携を簡単におこなう為のクラスが幾つか準備されています。
今回はそんな「いくつかの方法」を紹介したいと思います。
統一感を重んじてこの中の一つの方法で実装するもよし。臨機応変に使い分けて実装するもよし。

- **これからご紹介する方法では説明を簡単にする為にエラー処理などを省略しています。実装する場合には忘れずに。**
- **「他にもこんな方法があるよ」「この実装方法だとココがまずくない」とかありましたら是非ともコメント欄で教えて下さい。**
- **今回は[Doorkeeper](http://www.doorkeeper.jp/)のAPIからイベント情報を取得する事を前提としてサンプルを作っています。**

## NSURLConnectionのDelegateを使う方法

これはiOS SDKが初期の頃からある実装方法ですね。
Delegateを使ってデータを繋げてデータが揃ったところで処理を行う方法です。
エラー、データ取得時の処理がデリゲートメソッドとして別々に分かれているので、それぞれが処理をまとめて見える反面、NSURLConnectionの処理としては複数に分かれているので全体の処理を追う時には少し大変です。

```objc:Pattern1ViewController.m
- (void)viewDidLoad
{
  [super viewDidLoad];
  
  _eventData = [NSMutableData new];
  NSURL *url = [NSURL URLWithString:kEventUrl];
  NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
  NSURLConnection *urlConnection = [NSURLConnection connectionWithRequest:urlRequest
                                                                 delegate:self];
  if (urlConnection) {
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
  }
}

#pragma mark - NSURLConnection delegate.

- (void)connection:(NSURLConnection *)connection
    didReceiveData:(NSData *)data
{
  [_eventData appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
  _events = [NSJSONSerialization JSONObjectWithData:_eventData
                                            options:NSJSONReadingAllowFragments
                                              error:nil];
  dispatch_async(dispatch_get_main_queue(), ^{
    [self.tableView reloadData];
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
  });
}
```

## NSURLConnectionとGCDを使う方法

NSURLConnectionの同期処理であるsendSynchronousRequest:returningResponse:error:をGCDのバックグランド処理で囲んで非同期処理を実現する方法です。
これは他の人のソースを見ていて発見したんですが、初めて見た時は「なるほど！」っとなりました。
この方法は全体の処理がまとめて確認できるのでソースを追うのが楽になります。

```objc:Pattern2ViewController.m
- (void)viewDidLoad
{
  [super viewDidLoad];
  
  _eventData = [NSMutableData new];
  NSURL *url = [NSURL URLWithString:kEventUrl];
  NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
  
  [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
  
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    _eventData = [NSURLConnection sendSynchronousRequest:urlRequest
                                       returningResponse:nil
                                                   error:nil];
    dispatch_async(dispatch_get_main_queue(), ^{
      _events = [NSJSONSerialization JSONObjectWithData:_eventData
                                                options:NSJSONReadingAllowFragments
                                                  error:nil];
      [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
      [self.tableView reloadData];
    });
  }
```

## NSURLSessionを使う方法

最後にご紹介するのはiOS7から実装されたNSURLSessionを使う方法です。
先ほど紹介した「NSURLConnectionとGCDを使う方法」と同様に全体の処理が一箇所で確認できるのがいいですね。
まだこのクラスについては実践経験が乏しいのですが、ざっと調べた感じでは色々と便利な機能があるようです。

```objc:Pattern3ViewController.m
- (void)viewDidLoad
{
  [super viewDidLoad];

  NSURLSessionConfiguration *urlSessionConfiguration;
  urlSessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
  NSURLSession *urlSession = [NSURLSession sessionWithConfiguration:urlSessionConfiguration];
  NSURL *url = [NSURL URLWithString:kEventUrl];
  
  [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
  
  NSURLSessionDataTask *urlSessionDataTask;
  urlSessionDataTask = [urlSession dataTaskWithURL:url
                                 completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                   _events = [NSJSONSerialization JSONObjectWithData:data
                                                                             options:NSJSONReadingAllowFragments
                                                                               error:nil];
                                   dispatch_async(dispatch_get_main_queue(), ^{
                                     [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
                                     [self.tableView reloadData];
                                   });
                                 }];
  [urlSessionDataTask resume];
}
```

## まとめ

いろいろな方法を知っておくと、いざという時に役に立つかもしれませんので、皆さんもいろいろな方法を探してみてください。
最後に今回の記事のために作ったサンプルコードをgithubにおいておきます。

[tochi/iOSSecondStageAdventCaledar2013](https://github.com/tochi/iOSSecondStageAdventCaledar2013)

Let's enjoy the development.