2013年7月2日火曜日

ダウンロードファイルをNSDataで取得する方法



htmlのリンクでダウンロードするデータをNSDataで取得する一例です。ここでは説明を簡単にするためにPDFファイルとしていますが、それ以外の場合にも適用できます。

手順概要
  • UIWebViewDelegateのwebView:shouldStartLoadWithRequest:navigationType:メソッドでURLをチェック
  • PDFファイルの場合はNOを返し、UIWebViewから直接リクエストを送らないようする。(YESを返しても動作するが同じファイルを同時にリクエストすることになる?)
  • NSURLRequestを使ったリクエスト送信のメソッドを非同期で実行する。
  • NSURLRequestの受信データをNSDataに蓄積する。
  • NSURLRequestの受信完了でNSDataを使用する処理を実行する
実装例

storyboardでMyViewControllerのviewのクラスをUIWebViewに変更
viewのoutlets delegateをMyViewControllerに接続

//MyViewControllerにUIWebViewDelegateプロトコルを追加
@interface MyViewController : UIViewController <UIWebViewDelegate>

//インスタンス変数
@implementation FirstViewController
{
    NSURLConnection *_connection;
    NSMutableData *_data;
}

- (void)dealloc
{
    [_connection cancel];
    _connection = nil;
    _data = nil;
}

- (void)didReceiveMemoryWarning
{  
    [_connection cancel];
    _connection = nil;
    _data = nil;
    [super didReceiveMemoryWarning];
}

//画面表示時に検索ページを表示
- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    NSString *urlStr =
        [NSString stringWithFormat:@"http://www.google.co.jp/search?q=pdf"];  
    [self sendHttpRequest:[NSURL URLWithString:urlStr]];
}

//webView:shouldStartLoadWithRequest:navigationType:実装
- (BOOL)webView:(UIWebView *)webView
     shouldStartLoadWithRequest:(NSURLRequest *)request
                 navigationType:(UIWebViewNavigationType)navigationType
{
    //URLにPDFオープンパラメータが付いている場合を考慮
    NSRange range = [request.URL.absoluteString rangeOfString:@"\\.pdf(#.+|$)"
            options:NSRegularExpressionSearch|NSRegularExpressionCaseInsensitive];
    //PDFの場合はデータ取得
    if (range.location != NSNotFound) {
        [self sendHttpRequest:request];
        return NO;
    }
    //その他はUIWebViewにまかせる
    return YES;
}

//リクエスト送信
- (void)sendHttpRequest:(NSURLRequest *)request
{
//まだ受信が完了していない_connectionがあるかもしれないのでcancelしておく。
[_connection cancel];
    _connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
    if (_connection) {
        //受信データを格納するNSData
        _data = [NSMutableData data];
    } else {
        [(UIWebView *)self.view loadHTMLString:@"接続エラー" baseURL:nil];
    }
}

//レスポンス受信 - 念のため_dataを空にする
//Multipartの場合に複数回呼ばれる可能性あり
- (void)connection:(NSURLConnection *)connection
        didReceiveResponse:(NSURLResponse *)response
{
     [_data setLength:0];
}

//受信データの結合 - 複数回呼ばれる
- (void)connection:(NSURLConnection *)connention didReceiveData:(NSData *)data;
{
    [_data appendData:data];
}

//エラー発生時に呼ばれる
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
{
    _data = nil;
    _connection = nil;
}

//受信終了
- (void)connectionDidFinishLoading:(NSConnection*)connection;
{
    _connection = nil;
    //PDFをUIWebViewに表示する
    [self loadPdf];