iOSネットワークリクエスト(非同期)

前回に引き続き, ネットワークリクエストです。非同期で実際に利用されるコードを書きます。
ここでは, いくつかのプロとコロルを実装します。このサンプルでは, HTTPSはつかいません。
今まで実現できなかった, ダウンロードのプログレスや状態検出等ができます。
比較的データ量のある処理などに利用するとよいでしょう。

HTTPSは次の回にまわすか。

サンプル

NSURLConnectionDataDelegate, NSURLConnectionDelegate 
を実装します。

ヘッダ

@interface AsyncSample : NSObject<NSURLConnectionDataDelegate, NSURLConnectionDelegate>
@end

パラメータの外部公開を省略しています。

コード

@interface AsyncSample ()
@property (nonatomic) NSString *srcURL;
@property (nonatomic) NSURLConnection *conn;
@property (nonatomic) long total;
@property (nonatomic) NSMutableData *downloadData;
@end

@implementation AsyncSample

-(void)clear {
    self.total = 0;
    self.downloadData = [[NSMutableData alloc] init];
}

-(void)start {
    NSURL *url = [NSURL URLWithString:self.srcURL];
    NSURLRequest *req = [NSURLRequest requestWithURL:url];
    self.conn = [NSURLConnection connectionWithRequest:req delegate:self];
    // Start the connection
    [self.conn start];
}

-(void)startWithRunLoop {
    NSURL *url = [NSURL URLWithString:self.srcURL];
    NSURLRequest *req = [NSURLRequest requestWithURL:url];
    self.conn = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:NO];
    // Main roop
    [self.conn scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
    [self.conn start];
}


#pragma mark - 
#pragma mark - Delegate
-(NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response {
    
    // Redirect?
    // You can add additional things for request
    return request;
}

#pragma mark - Complete Response
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    // Get complete response
    
    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
    
    if ( httpResponse.statusCode != 200 ) {
        // Something wrong.
        NSLog(@"Something wrong");
        [connection cancel];
        return;
    }
    
}

#pragma mark - Receive Data
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    // How many bytes in this chunk
    self.total += [data length];  // Add total
    [self.downloadData appendData:data];
}

#pragma mark - Failed
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    NSLog(@"Load failed with error %@", [error localizedDescription]);
    // Error handling
    // Close file delete tmp file or something
}

#pragma mark - Entire request has benn loaded, data was finished
-(void) connectionDidFinishLoading:(NSURLConnection *)connection {
    // File operation or complete operations
}

@end

必要のないコードも一部混じっていますが, clearで初期化, startで処理をスタートしています。
残りはプロトコルの実装です。
エラー処理など一部省略しています

self.conn = [NSURLConnection connectionWithRequest:req delegate:self];

でdelegateを設定して, 処理をdelegationしています。

Protocol

実装しているメソッドを簡単にみていきます

メソッド 説明
-(NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)response リダイレクト処理が入った場合に実行
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response レスポンスが返ってきたとき
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 何かしらデータをダウンロードした場合(データを得るたびに実行)
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 失敗した場合(何かエラーが発生したらその時点で)
-(void) connectionDidFinishLoading:(NSURLConnection *)connection 処理が完全に終了

ファイルのダウンロードだけが目的ならライブラリASIHTTPRequestとかを使った方が早い気がします。セキュリティやどうしても何か処理を入れたい場合は, じっくり実装するしかないですね。