※本記事は、旧ブログからの再掲です。
iPhoneアプリとサーバーとの通信方法には、同期通信と非同期通信があります。
同期通信では、サーバーにリクエストを送り、そのレスポンスが返ってきてデータを全て受信するまで待ちます。その間、次の処理に遷移することはできません。ユーザーの画面操作にも反応できないため、すぐに処理が完了する場合や次の処理に遷移するにはサーバーからの返答が必要な場合などに使用することになると思います。
非同期通信では、サーバーにリクエストを送った後そのレスポンスを待つ必要はなく、次の処理に遷移できます。サーバーからレスポンスが返ってきてデータを全て受信すると予め指定してあった処理が呼び出され、必要な処理を行うことができます。
今回は、iPhone側からリクエストを送り、レスポンスをXMLで受け取る方法です。
同期通信
NSURLConnection の sendSynchronousRequest:returningResponse:error: というメソッドを使用してサーバーにリクエストを送信します。
リクエスト情報、レスポンス情報格納エリア(ポインタ)、エラー情報格納エリア(ポインタ)を引数で渡します。
リクエスト情報(IN):NSURLRequest *
レスポンス情報格納エリア(OUT):NSURLResponse **
エラー情報格納エリア(OUT):NSError **
サーバー側で処理が終了しレスポンスが返ってくると戻り値として、NSDataが返されます。
今回の場合には、XMLデータが返されるので、XMLParserで解析しています。
レスポンス情報は以下に示した通り、いろいろな情報が得られますが、statusCodeだけ見て処理を行っています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
// サーバーへリクエストを送信 NSURL *url = [NSURL URLWithString:@"http://www.sample.com/login.php"]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; NSString *post = [NSString stringWithFormat:@"login_id=%@&password=%@", login_id, password]; NSData *postData = [post dataUsingEncoding:NSUTF8StringEncoding]; NSURLResponse *response = nil; NSError *error = nil; [request setHTTPMethod:@"POST"]; [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"content-type"]; [request setHTTPBody:postData]; NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; // エラー情報 if ( error ) { NSLog(@"Connection failed. Error - %@ %d %@", error.domain, error.code, error.localizedDescription); return; } // レスポンス情報 NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; NSLog(@"expectedContentLength:%lld", httpResponse.expectedContentLength); NSLog(@"MIMTType:%@", httpResponse.MIMEType); NSLog(@"suggestedFieldname:%@", httpResponse.suggestedFilename); NSLog(@"textEncodingName:%@", httpResponse.textEncodingName); NSLog(@"URL:%@", httpResponse.URL); NSLog(@"statusCode:%d", httpResponse.statusCode); NSLog(@"localizedStringForStatusCode:%@", [NSHTTPURLResponse localizedStringForStatusCode:httpResponse.statusCode]); if ( httpResponse.statusCode != 200 ) { NSLog(@"statusCode:%d (%@)", httpResponse.statusCode, [NSHTTPURLResponse localizedStringForStatusCode:httpResponse.statusCode]); return; } // NSDataをXMLParserで解析 if ( ! data ) { NSLog(@"data:nil"); return; } XMLParser *parser = [[XMLParser alloc] init]; NSArray *xmlData = [[NSArray alloc] init]; xmlData = [parser parse:data]; NSString *result = xmlData[0]; NSLog(@"result:%@", result); |
非同期通信
NSURLConnectionのinitWithRequest:delegate:というメソッドを使用してサーバーにリクエストを送信します。
リクエスト情報、デリゲートクラスのインスタンスを引数で渡します。
リクエスト情報(IN):NSURLRequest *
デリゲートクラスのインスタンス(IN):id
レスポンスは、デリゲートメソッドが受信します。
以下4つのdelegateメソッドの実装が必要となります。
・connection:didReceiveResponse:(レスポンス受信時に1回のみ)
・connection:didReceiveData:(コンテンツデータ受信時。断片的なデータを通信が終了するまで何度も)
・connection:didFailWithError:(エラー発生時)
・connectionDidFinishLoading:(通信完了時に1回のみ)
今回は、サーバーとの送受信を行うクラス(NetworkConnector)を用意し、そちらでリクエスト送信とレスポンス受信を行っています。
また、デリゲート処理側では、受信完了時にサーバー側からのレスポンスデータを正常に受信できたか判断し、メイン処理側のメソッドを呼び出すようにしています。正常に受信出来ていた場合には、メイン処理側で取得したデータ(XML)を解析しています。
■ メイン処理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
// サーバーへリクエスト送信 NetworkConnector *connector = [[NetworkConnector alloc] initWithDelegate:self]; NSURL *url = [NSURL URLWithString:@"http://www.sample.com/login.php"]; NSString *post = [NSString stringWithFormat:@"login_id=%@&password=%@", login_id, password]; NSData *postData = [post dataUsingEncoding:NSUTF8StringEncoding]; [connector openUrl:url postData:postData]; /* * 受信成功 */ - (void)receiveSucceed:(id)sender { // XMLを解析する NetworkConnector *connector = (NetworkConnector *)sender; XMLParser *parser = [[XMLParser alloc] init]; NSArray *xmlData = [parser parse:connector.receivedData]; NSString *result = xmlData[0]; NSLog(@"result:%@", result); : (略) : } /* * 受信失敗 */ - (void)receiveFailed { : (略) : } |
■ サーバーと送受信を行うクラス
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
// // NetworkConnector.h // @protocol NetworkConnectorDelegate; @interface NetworkConnector : NSObject @property (weak, nonatomic) id<NetworkConnectorDelegate> delegate; // デリゲート @property (readonly) NSData *receivedData; // 受信データ - (void)openUrl:(NSURL *)url postData:(NSData *)postData; @end /* * Protocol for Network connector delegate. */ @protocol NetworkConnectorDelegate <NSObject> @required - (void)receiveSucceed:(id)sender; - (void)receiveFailed:(id)sender; @end |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
// // NetworkConnector.m // #import "NetworkConnector.h" @implementation NetworkConnector { NSMutableData *_receivingData; } /* * 初期処理 */ - (id)init { self = [super init]; if ( self ) { } return self; } /* * ネットワーク接続 */ - (void)openUrl:(NSURL *)url postData:(NSData *)postData { _receivingData = [[NSMutableData alloc] init]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0]; [request setHTTPMethod:@"POST"]; [request setHTTPBody:postData]; [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"content-type"]; NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; if ( ! connection ) { NSLog(@"NSURLConnection error"); } } /* * レスポンス受信 */ - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response { // レスポンスヘッダ情報表示 NSLog(@"expectedContentLength:%lld", response.expectedContentLength); NSLog(@"MIMTType:%@", response.MIMEType); NSLog(@"suggestedFieldname:%@", response.suggestedFilename); NSLog(@"textEncodingName:%@", response.textEncodingName); NSLog(@"URL:%@", response.URL); NSLog(@"statusCode:%d", response.statusCode); NSLog(@"localizedStringForStatusCode:%@", [NSHTTPURLResponse localizedStringForStatusCode:response.statusCode]); NSDictionary *dict = response.allHeaderFields; NSArray *allKeys = dict.allKeys; int count = allKeys.count; NSString *key; NSString *value; for ( int i = 0; i < count; i++ ) { key = allKeys[i]; value = (NSString *)[dict valueForKey:key]; NSLog(@"header %@:%@", key, value); } // Cookie情報表示 NSArray *allCookies = [NSHTTPCookie cookiesWithResponseHeaderFields:response.allHeaderFields forURL:[NSURL URLWithString:@"http://www.sample.com"]]; NSLog(@"How many Cookies:%d", allCookies.count); for ( NSHTTPCookie *cookie in allCookies ) { NSLog(@"Cookie name:%@ value:%@ expire:%@", cookie.name, cookie.value, cookie.expiresDate); } // ステータスコード:200(OK)以外 if ( response.statusCode != 200 ) { [connection cancel]; [self connection:connection didFailWithError:nil]; return; } } /* * コンテンツ受信 */ - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { // 現在の受信済みデータに追加 [_receivingData appendData:data]; } /* * エラー発生時 */ - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { NSLog(@"Connection failed. Error - %@ %d %@", error.domain, error.code, error.localizedDescription); if ( self.delegate ) { [self.delegate performSelector:@selector(receiveFailed:) withObject:self]; } _receivingData = nil; } /* * すべての受信完了 */ - (void)connectionDidFinishLoading:(NSURLConnection *)connection { if ( ! _receivingData || _receivingData.length == 0 ) { NSLog(@"データの復元に失敗しました"); if ( self.delegate ) { [self.delegate performSelector:@selector(receiveFailed:) withObject:self]; } return; } _receivedData = [[NSData alloc] initWithData:_receivingData]; if ( self.delegate ) { [self.delegate performSelector:@selector(receiveSucceed:) withObject:self]; } _receivingData = nil; } @end |
<参考>
・ [Appleドキュメント] ネットワーキングオーバービュー