ASIHTTPRequestクラス群で同期通信・非同期通信する | 成長の果実

成長の果実

不完全でも良いから前に進む。

iPhoneアプリで同期通信・非同期通信を実装したい場合に、ASIHTTPRequestというクラス群(他にも色々なクラスが入ってる)を使うと割と簡単に実装できる。


今回は、ファイルのアップロードを行うのでASIFormDataRequestクラスを使用することにする。
ついでにプログレスバーで進捗状況も確認できるようにしてみる。


まずはダウンロード。

ASIHTTPRequest Documentation - All-Seeing Interactive
http://allseeing-i.com/ASIHTTPRequest/

latest version のものをダウンロードする。

$成長の果実-ASIFormDataRequest01



次に、ダウンロードしたファイルの中にある、Classesの中身全部とExternalの中にあるReachabilityを自分のプロジェクトに取り込む。

Reachability は一見不要そうだけど、追加しないとASIHTTPRequestクラス群が使えない。


それと、ASIHTTPRequestクラス群を使用するにあたり必要な、下記のフレームワークとライブラリも追加する。追加しないとASIHTTPRequestクラス群が使えないので注意。

iOS4に含まれているので普通に追加すればOK.

  • CFNetwork.framework
  • SystemConfiguration.framework
  • MobileCoreServices.framework
  • libz.1.2.3.dylib


    追加後のイメージはこんな感じ。

    $成長の果実-ASIFormDataRequest02



    下準備は整ったので、次はコードを書いて実装していく。

    実装する機能は以下の二点。

  • ボタンを押すとファイルがサーバ(PHPで処理)へ非同期通信でアップロードされる。
  • スイッチの切り替えでプログレスバーを使用するかどうか選べる。


    アプリ起動時に最初に呼び出される FirstViewController に処理を書いた。

    下記、コード。

    主要部分だけを説明していく。赤字の部分がポイント箇所。


    ◎FirstViewController.h

    #import <UIKit/UIKit.h>
    #import "ASIFormDataRequest.h"
    #import "ASINetworkQueue.h"



    @interface FirstViewController : UIViewController {
    UIProgressView *pb; // プログレスバー
    UISwitch *sw; // スイッチ
    }

    @end


    ASINetworkQueue.h はプログレスバーで進捗状況を確認するのに使う。
    進捗状況を確認しないのであれば、importしないでOK.


    ◎FirstViewController.m

    #import "FirstViewController.h"


    @implementation FirstViewController

    - (void)dealloc
    {
    [pb release];
    [sw release];
    [super dealloc];
    }

    - (void)viewDidLoad
    {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.

    // ボタン表示
    [self uplaodFileButton];

    // プログレスバー表示
    [self progressBar];

    // ラベルを表示
    [self label];

    // スイッチ表示
    [self switchPb];
    }

    //--------------------------------------------------
    // ファイルアップロードボタン
    //--------------------------------------------------
    // ボタンを追加
    - (void)uplaodFileButton
    {
    UIButton *bt = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    bt.frame = CGRectMake(60, 150, 200, 40);
    [bt setTitle:@"ファイルアップロード" forState:UIControlStateNormal];
    [bt addTarget:self action:@selector(uplaodDataButtonAction:)forControlEvents:UIControlEventTouchDown];
    [self.view addSubview:bt];
    }

    // ボタンアクション
    - (void)uplaodDataButtonAction:(UIButton*)button
    {
    // アップロード
    [self uploadStart];
    }


    //--------------------------------------------------
    // プログレスバー
    //--------------------------------------------------
    // プログレスバーを追加
    - (void)progressBar
    {
    pb = [[[UIProgressView alloc]
    initWithProgressViewStyle:UIProgressViewStyleDefault] autorelease];
    pb.frame = CGRectMake(60, 20, 200, 10);
    pb.progress = 0.0;
    [self.view addSubview:pb];
    }


    //--------------------------------------------------
    // ラベル
    //--------------------------------------------------
    // ラベルを追加
    - (void)label
    {
    UILabel *label = [[UILabel alloc] init];
    label.frame = CGRectMake(15, 265, 200, 50);
    label.textColor = [UIColor blackColor];
    label.font = [UIFont systemFontOfSize:[UIFont systemFontSize]];
    label.textAlignment = UITextAlignmentLeft;
    label.text = @"プログレスバーを使用する";
    [self.view addSubview:label];
    }


    //--------------------------------------------------
    // スイッチ
    //--------------------------------------------------
    // スイッチを追加
    - (void)switchPb
    {
    sw = [[[UISwitch alloc] init] autorelease];
    sw.center = CGPointMake(250, 290);
    sw.on = NO;
    [self.view addSubview:sw];
    }


    //--------------------------------------------------
    // アップロード処理
    //--------------------------------------------------
    - (void)uploadStart {
    NSURL *url = [NSURL URLWithString:@"http://localhost/test/uploadsample.php"];
    ASIFormDataRequest *request = [[[ASIFormDataRequest alloc] initWithURL:url] autorelease];

    [request setPostValue:@"hoge" forKey:@"file_name"]; // ファイル名(仮名:hoge)
    [request setPostValue:@"jpg" forKey:@"extension"]; // 拡張子

    // データをセット
    NSString *path = [[NSBundle mainBundle] pathForResource:@"A5B8A1BCA5D7A3B1" ofType:@"jpg"];
    NSData *image = [NSData dataWithContentsOfFile:path];
    [request setData:image forKey:@"upfile"];

    [request setTimeOutSeconds:120];
    [request setDelegate:self];
    [request setDidFinishSelector:@selector(postSucceeded:)];
    [request setDidFailSelector:@selector(postFailed:)];
    [request setDefaultResponseEncoding:NSUTF8StringEncoding];

    if (sw.on == 0) {
    // プログレスバーを使用せずに非同期通信する場合に使用
    [request startAsynchronous];

    NSLog(@"プログレスバー未使用");
    } else {
    // プログレスバーを使用する
    ASINetworkQueue *networkQueue = [[ASINetworkQueue alloc] init];
    [networkQueue setUploadProgressDelegate:pb];
    [networkQueue setShowAccurateProgress:YES];
    [networkQueue addOperation:request]; // 非同期通信
    [networkQueue go];

    NSLog(@"プログレスバー使用");
    }
    }

    - (void)postSucceeded:(ASIFormDataRequest *)request
    {
    NSString *resString = [request responseString];
    NSLog(@"%@", resString);
    }

    - (void)postFailed:(ASIFormDataRequest *)request
    {
    NSString *resString = [request responseString];
    NSLog(@"%@", resString);
    }


    @end



    [request startAsynchronous]; のところは、 [request startSynchronous]; にすると同期通信になるはず。


    ついでにサーバー側の処理(PHP)のコードも。

    ◎uploadsample.php

    <?php
    $file_name = $_POST["file_name"];
    $extension = $_POST["extension"];

    if (is_uploaded_file($_FILES["upfile"]["tmp_name"])) {
    if (move_uploaded_file($_FILES["upfile"]["tmp_name"], "./" . $file_name . "." . $extension)) {
    echo $file_name . "." . $extension . "をアップロードしました。";
    } else {
    echo "ファイルをアップロードできません。";
    }
    } else {
    echo "ファイルが選択されていません。";
    }
    ?>



    以上。


    ちゃんとファイルがアップロードできるか確認。


    アプリを起動をして、「ファイルアップロード」ボタンを押下。

    成長の果実-ASIFormDataRequest03


    うーん・・・目に見えて変化がないから分からないけど、実際にはちゃんとファイルがアップロードされてるはず。

    Terminalで確認してみる。

    成長の果実-ASIFormDataRequest05

    あった!!hoge.jpg!


    データ内容にも問題がないか確認。

    成長の果実-ASIFormDataRequest06


    うん、OK.


    最後に、ファイルをアップロードするっていう処理自体は同じだけど、プログレスバーを使用してアップロード状況も確認してみる。

    成長の果実-ASIFormDataRequest04

    こっちのほうが目に見えて分かりやすい。

    もちろんアップロードされた画像も問題なく表示できました。



    ちなみに、FirstViewController.m の

    // データをセット
    NSString *path = [[NSBundle mainBundle] pathForResource:@"A5B8A1BCA5D7A3B1" ofType:@"jpg"];
    NSData *image = [NSData dataWithContentsOfFile:path];
    [request setData:image forKey:@"upfile"];



    の部分を省けば、ただのVALUE値をPOSTするだけになる。

    文字列だけを送信して、サーバ側で何か処理をさせたいとき(DB処理とか)にも使える。


    次回はBASIC認証機能を説明しようかな。


    ----------
    サンプルソース:https://github.com/tetsuco/SampleASIFormDataRequest_with_srv