unoh.github.com

iPhone SDKでウェブAPIコール

Fri Jun 04 00:26:14 -0700 2010

今さらですが最近iPhone SDKプログラミングを始めたBrandonです。

勉強目的に簡単なアプリ作ろうと思って、今個人的にとても気に入っているウェブサービス(Posterous)のiPhoneアプリを作っています。
アプリでWeb APIリクエスト・レスポンスの処理をする必要があったので、
ド素人ですが下記のような感じで初期実装してみました。
暇がある時に遊び心で触っている程度だけなので、やり方が間違っているところもたくさんあるかも知れないが、何かご指摘があれば遠慮なく突っ込んで頂けるとありがたいです。

導入したライブラリ


最初に問題になったのは、Posterous APIはBasic Authentication使っていますが、調べてみたところObjective Cにはbase64エンコードのライブラリがないことが判明しました。
そこで、Objective Resourceという良さそうなフレームワークを見つけたので、それを導入しました。(base64エンコードのためにそこまでする必要はないが、他にも勉強になりそうな部分があるフレームワークなのでそういうところを含めて入れてみました。)

XMLの解析には、GoogleのGDataXMLを使用しました。

今回は、PosterousのgetSites APIをコールします。

リクエスト処理クラス


リクエスト周りの処理はPosterousRequest.hとPosterousRequest.mにまとめました。
//
//  PosterousRequest.h
//

#import <Foundation/Foundation.h>
#import "NSData+Additions.h" //Objective Resourceから

@interface PosterousRequest : NSObject {
	//受信データを保存する変数
	NSMutableData *receivedData; 
}

@property(nonatomic,retain) NSMutableData *receivedData;

//PosterousのgetSites APIコール
- (void)getSites:(NSString*)username password:(NSString*)password; 

- (void)dealloc;

//受信する時に呼び出される関数
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;

@end


PosterousRequest.m

//
//  PosterousRequest.m
//

#import "PosterousRequest.h"
#import "PosterousAppDelegate.h"//アプリケーションのメインコントローラ
#import "GDataXMLNode.h" //GoogleのXML処理ライブラリ

@implementation PosterousRequest

//@synthesizeはクラスの基本的なgetやset関数を自動的に生成してくれます
@synthesize receivedData; 

/**
 * リクエスト(requestObj)に認証情報をつける関数
 * http://www.wetware.co.nz/blog/2009/02/iphone-uiwebview-http-basic-authentication/
 */
- (void) addAuthToWebRequest:(NSMutableURLRequest*)requestObj username:(NSString*)username password:(NSString*)password{
	
	//ここでobjective resourceのライブラリが使われます
	NSString *authString = [[[NSString stringWithFormat:@"%@:%@", username, password] dataUsingEncoding:NSUTF8StringEncoding] base64Encoding];
	
	authString = [NSString stringWithFormat: @"Basic %@", authString];
	
	[requestObj setValue:authString forHTTPHeaderField:@"Authorization"];
}

/**
 * リクエストを送信する
 */
- (void)sendRequest:(NSString*)address username:(NSString*)username password:(NSString*)password {
	
	//リクエストの初期設定
	NSString *urlString = [NSString stringWithFormat:address];
	NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
	[request setURL:[NSURL URLWithString:urlString]];
	[request setHTTPMethod:@"POST"];
	
	//上記のaddAuthToWebRequestで認証情報をリクエストに追加します
	[self addAuthToWebRequest:request username:username password:password];
	
	/*
	  Bodyなどの設定
	*/

	NSLog(@"connection attempted");
	//PS:"@"はchar*をObjective CのNSStringにコンバートします+Unicode対応をつける
	
	[NSURLConnection connectionWithRequest:request delegate:self];
} 

//getSites APIリクエスト
-(void)getSites:(NSString*)username password:(NSString*)password {
	[self sendRequest:@"https://posterous.com/api/getsites"username:username password:password];
}

//最初にレスポンスが来たとき一度だけだけ実行されます
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {

	//receivedDataを初期化してデータ受信の準備をする
	receivedData = [[NSMutableData alloc]init];
	[receivedData setLength:0];
	NSLog(@"Set received data length to 0");
	
	//レスポンスのヘッダー情報をNSLogでコンソールに出力して確認する
	if ([response respondsToSelector:@selector(allHeaderFields)]) {
		NSLog(@"response header");
		NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
		NSDictionary *dictionary = [httpResponse allHeaderFields];
		NSLog(@"%@", [dictionary description]);
	}
}

//受信したデータをreceivedDataに保存する
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
	[receivedData appendData:data];
}

//レスポンスが終了したときに実行されます
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
	NSError *error;
	NSLog(@"succeeded! received %d bytes of data", [receivedData length]);
	GDataXMLDocument *doc = [[GDataXMLDocument alloc] initWithData:receivedData options:0 error:&error];
	if (doc != nil) {
		/*
		 ...
		 レスポンス解析
		 ...
		 */
	}

	/*  
	  ..
	  画面遷移処理など
	  ..
	*/
	[doc release];
	[receivedData release];
}

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

@end


実際にコントローラでAPIをコールするときの例:
posterousRequest = [[PosterousRequest alloc] init];
[posterousRequest getSites:self.username.text password:self.password.text];
[posterousRequest release];


以上です!