libro
www.tuyano.com
初心者のためのObjective-Cプログラミング入門

NSURLとNSURLConnection (6/6)

作成:2011-02-24 09:26
更新:2011-11-13 22:01

■非同期通信を行う

では、実際に非同期通信を行ってみましょう。これも、やっぱりサンプルコードを先に見てもらったほうがわかりやすいでしょう。

下のリスト欄にあげたのが、www.apple.comに非同期で接続し、データを受け取るサンプルです。ここでは「SampleConnectDelegate」というデリゲートクラスを定義しておき、その中で非同期通信の処理を行っています。実際にデータが受信できるか確かめてみましょう。

なお、面倒くさいので、ここでは受け取ったバイナリデータのまま出力してあります。気になるなら、先に上げたサンプルのようにNSStringを生成して出力するように直してみましょう。

さて、まずは非同期通信をどのように行っているのか、main関数の処理を見てみましょう。これは、実は動機つ心よりも簡単です。NSURLResponseNSErrorがいらないのですから。
NSURLConnection* connection = [NSURLConnection 
        connectionWithRequest:request  delegate:delegate];
これが、非同期通信を行っている部分です。引数には、NSURLRequestと、デリゲートクラスのインスタンスが渡されています(デリゲートクラスは、ごく当たり前にallocしてinitしてautoreleaseしてインスタンスを作っています)。通信そのものは、これでおしまいです。後はNSURLConnectionが適当にやってくれるんですから。

では、非同期通信のキモであるデリゲートクラスを見てみましょう。SampleConnectDelegateクラスでは、「NSMutableData* result;」というインスタンス変数が用意されています。このNSMutableDataというのは、バイナリデータを扱うNSDataのサブクラスで、データの編集が可能なように機能拡張されたものです。つまり「あれこれ操作できるNSData」というわけですね。非同期で受け取ったデータを、ここに保管していこう、というわけです。では、それぞれのメソッドを見てみましょう。
- (void)connection:(NSURLConnection *)connection
    didReceiveResponse:(NSURLResponse *)response
まずは、レスポンスが返ってきたときの処理です。ここで、NSMutableDataインスタンスを作成し初期化しています。データ受信のための準備を行っているわけですね。
- (void)connection:(NSURLConnection *)connection
        didReceiveData:(NSData *)data
これは、データを受信したときの処理でした。ここでは、NSMutableDataの「appendData:」というメソッドを呼び出して、受け取ったデータを追加しています。このメソッドでは、接続しているNSURLConnectionと、受け取ったデータが保管されているNSDataがそれぞれ引数として渡されます。このNSDataを、インスタンス変数のNSMutableDataに追加していくわけです。
- (void)connectionDidFinishLoading:
        (NSURLConnection *)connection
通信完了時の処理です。ここでは、インスタンス変数のNSMutableDataNSLogで出力しています。ここでは単にそのまま書き出しているだけですが、必要に応じてNSDataからNSStringに戻したり、あるいは受け取ったデータをファイルに保存したりといった処理も、ここで行えばよいでしょう。


◯[[NSRunLoop currentRunLoop] run]; について◯
これで非同期通信についてはおしまいですが、実はもう1つ、注意すべきポイントがあります。それは、main関数のおしまいの方にある[[NSRunLoop currentRunLoop] run];というものについてです。

このNSRunLoopというのは、「実行ループ」と呼ばれるものに関するクラスです。これは、要するにメインスレッドをぐるぐるループして実行させるものです。例えば、GUIを使ったアプリケーションなどで用いられます。

ここでは、プログラムを終了させないために、わざと実行ループを動かして、プログラムが永遠に終わらないようにしてあります(ですから、適当なところで強制終了してください)。なんでそんなことを?と思った人。なぜって、非同期通信は、通信を開始してもそのまま処理を続けて実行してしまうからです。すると、あっという間にmain関数の実行を終え、プログラムは終了してしまいます。まだ非同期通信をやってる途中だっていうのに……。そこで、勝手にプログラムが終了しないように、こうしてプログラムを待たせているのです。

試しに、この[[NSRunLoop currentRunLoop] run];を削除して実行してみましょう。プログラムはなにもしないでそのまま終了してしまいます。別に何もしてないわけではなくて、非同期通信が終わる前にプログラムが終了してしまっているのです。

※プログラムリストが表示されない場合

AddBlockなどの広告ブロックツールがONになっていると、プログラムリスト等が表示されない場合があります。これらのツールをOFFにしてみてください。

●プログラム・リスト●

#import <Foundation/Foundation.h>

// デリゲートクラスの宣言
@interface SampleConnectDelegate : NSObject {
	NSMutableData* result;
}
@end

// デリゲートクラスの実装
@implementation SampleConnectDelegate

- (void)connection:(NSURLConnection *)connection
didReceiveResponse:(NSURLResponse *)response {
	result = [[NSMutableData alloc] init];
}

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

- (void)connectionDidFinishLoading:
(NSURLConnection *)connection {
	NSLog(@"%@",result);
}

@end

// メイン関数
int main (int argc, const char * argv[]) {
    @autoreleasepool {
        NSString* address = @"http://www.apple.com/";
        NSURL* url = [NSURL URLWithString:address];
        NSURLRequest* request = [NSURLRequest 
                                 requestWithURL:url];
        SampleConnectDelegate* delegate = 
        [[SampleConnectDelegate alloc] init];
        NSURLConnection* connection = 
        [NSURLConnection 
         connectionWithRequest:request 
         delegate:delegate];
        if (!connection) {
            NSLog(@"Error...");
        }
        
        // 終了しないようにしておく
        [[NSRunLoop currentRunLoop] run];
    }
    return 0;
}
※関連コンテンツ

「初心者のためのObjective-Cプログラミング入門」に戻る