출처 :http://alones.kr/tag/nsurlrequest
Aug 23
iPhone은 NSURLRequest와 NSURLConnection 를 이용해서 http request와 response를 쉽게 처리할 수 있게 해준다.
첫 아이폰 앱이었던 Make Num을 개발할 때 http request/response를 위한 유틸 클래스를 만들었던 것을 이용해, http request로 이미지를 받아서 보여주는 것에 대해 다루는 튜토리얼이다.
Make Num 때에는 Ranking 서버에서 점수와 해당 정보를 받아오는 것을 string으로 받아올 때 사용했다.
.
App to Make in this tutorial
이번 튜토리얼에서 만들 앱은 아래 Picasa에 있는 이미지를 받아서 UIImageView에 뿌려주는 간단한 앱이다.
http://lh4.ggpht.com/_85hIOLhClFE/SpAB03RUZtI/AAAAAAAAFgs/VdhbDuH8riQ/sample.png
Simulator에서 실행시킨 모습은 아래와 같다 (싱가폴에서 찍은 사진이다. ㅋ).
.
HttpManager
HttpManager는 URL Loading System Guide 문서를 보고 만든 Class이다.
URL을 String으로 주면, 해당 주소의 웹페이지를 읽어서 NSMutableData로 전달해준다. 이 Tutorial의 경우는 웹 페이지가 image이기 때문에 NSMutableData로 UIImage를 만들면 되고, 페이지가 문자열일 경우는 NSString을 만들어서 처리하면 될 것이다.
HttpManager를 사용하기 위해서는 Caller가 HttpManagerDelegate를 Adopt 하게 했다. Http request 시 callback 되는 method들을 처리해주기 위해서이다.
HttpManager를 들여다보자.
.
HttpManager Class 선언 부
HttpManagerDelegate를 받은 Caller를 받기 위한 delegate와 response data를 받기 위한 received data를 가지고 있다.
01 |
@protocol HttpManagerDelegate; |
03 |
@interface HttpManager : NSObject { |
07 |
NSMutableData *receivedData; |
10 |
@property (nonatomic, assign) id delegate; |
11 |
@property (nonatomic, retain) NSMutableData *receivedData; |
.
HttpManagerDelegate protocol
HttpManagerDelegate protocol은 http request 시 request가 완료되었을 때와 실패했을 때 callback 되는 method들을 정의하고 있다. 그 외 request 시 callback 되는 NSURLConnectionDelegate의 connection method들은 내부적으로 처리했다.
1 |
@protocol HttpManagerDelegate |
3 |
-( void )connectionDidFail:(HttpManager*)aHttpManager; |
4 |
-( void )connectionDidFinish:(HttpManager*)aHttpManager; |
.
[HttpManager initWithUrl: delegate:]
HttpManager를 initWithUrl로 init 하면 바로 주어진 url의 loading을 시작한다. 즉, url에 대해서 NSURLRequest를 만들고, NSURLConnection 생성해서 loading을 시작한다. 여기서 NSString의 URL을 [NSString stringByAddingPercentEscapesUsingEncoding:]에 NSUTF8StringEncoding을 지정해서 encoding하는 것을 잊지 말아야 한다. 공백이나 특수 문자 등을 ‘%’를 써서 encoding 해준다.
01 |
-(id)initWithUrl:(NSString*)aURL delegate:(id)aDelegate { |
03 |
if ( self = [super init] ) { |
06 |
self.delegate = aDelegate; |
09 |
NSString *escapedUrl = [aURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; |
12 |
NSURLRequest *aRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:escapedUrl] |
13 |
cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0]; |
16 |
NSURLConnection *aConnection=[[NSURLConnection alloc] initWithRequest:aRequest delegate:self]; |
21 |
receivedData = [[NSMutableData data] retain]; |
.
[HttpManager connectionDidFinishLoading:]
HttpManager의 다른 method들은 간단하며 HttpManagerDelegate를 adopt 한 caller의 해당 method를 불러주기 위해 caller가 해당 method를 가지고 있는지 체크하는 코드를 보라고 connectionDidFinishLoading method 코드를 보여준다. Caller의 connectionDidFinishLoading method가 불리면 Caller는 HttpManager의 receivedData를 받아서 사용하면 된다.
01 |
- ( void )connectionDidFinishLoading:(NSURLConnection *)connection { |
03 |
if ( [self.delegate respondsToSelector:@selector(connectionDidFail:)]) { |
04 |
[self.delegate connectionDidFinish:self]; |
08 |
if ( receivedData != nil) { |
09 |
[receivedData release]; |
.
UI 부분 완성하기
이 번에도 IB (Interface Builder) 없이 간단하게 UI를 만들겠다.
시나리오는 아래와 같다.
1. applicationDidFinishLaunching 에서 UIImageView, UIActivityIndicatorView를 생성하고 Indicator Animation을 start한 후 HttpManager에 Picasa의 이미지를 가져오게 http request를 요청한다.
2. HttpManagerDelegate의 connectionDidFinish 가 callback 되면 HttpManager의 receivedData를 가져와서 UIImage를 만들고 UIImageView에 넣어준다.
.
URLLoadingSystem_imageAppDelegate class 선언
URLLoadingSystem_imageAppDelegate는 HttpManagerDelegate를 adopt해서 아래와 같다.
02 |
#import "HttpManager.h" |
04 |
@interface URLLoadingSystem_imageAppDelegate : NSObject { |
07 |
UIImageView *imageView; |
08 |
UIActivityIndicatorView *indicator; |
10 |
HttpManager *httpManager; |
11 |
NSMutableData *receivedData; |
14 |
@property (nonatomic, retain) IBOutlet UIWindow *window; |
15 |
@property (nonatomic, retain) UIImageView *imageView; |
17 |
-( void )getImageFrom:(NSString*)url; |
.
UIApplicationDelegate의 applicationDidFinishLaunching
위에서 설명한 것과 같이 UIImageView를 생성해서 UIWindow에 add하고 UIActivityIndicatorView를 생성해서 UIImageView에 add 후 animation을 시작하고 HttpManager를 picasa url로 init해서 URL Loading을 시작한다.
01 |
- ( void )applicationDidFinishLaunching:(UIApplication *)application { |
05 |
imageView = [[UIImageView alloc] initWithFrame:window.frame]; |
06 |
[window addSubview:imageView]; |
09 |
indicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake( window.frame.size.width/2 - 20, window.frame.size.height/2-20, 40, 40)]; |
10 |
indicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge; |
11 |
[imageView addSubview:indicator]; |
12 |
[indicator startAnimating]; |
17 |
[window makeKeyAndVisible]; |
20 |
-( void )getImageFrom:(NSString*)url { |
22 |
[httpManager release]; |
26 |
httpManager = [[HttpManager alloc] initWithUrl:url delegate:self]; |
.
HttpManagerDelegate의 connectionDidFinish를 adopt
connectionDidFinish: 는 URL Loading이 완료되었을 때 callback 된다. 여기서 HttpManager의 receivedData를 가져와서 아래와 같이 UIImage를 생성해서 UIImageView에 넣어주면 완료된다.
1 |
#pragma mark HttpManagerDelegate |
2 |
-( void )connectionDidFinish:(HttpManager*)aHttpManager { |
3 |
[indicator stopAnimating]; |
5 |
receivedData = httpManager.receivedData; |
6 |
imageView.image = [[UIImage alloc] initWithData:receivedData]; |
.
Http Request Fail 처리
HttpManagerDelegate의 connectionDidFail은 Http Request가 실패했을 때 callback 된다. 아래와 같이 사용자에게 실패했다는 메시지를 UIAlertView로 보여준다.
1 |
-( void )connectionDidFail:(HttpManager*)aHttpManager { |
2 |
[indicator stopAnimating]; |
4 |
UIAlertView *alertView = [[[UIAlertView alloc] initWithTitle:@ "Fail" message:@ "Couldn't connect" delegate:self cancelButtonTitle:@ "OK" otherButtonTitles:nil, nil] autorelease]; |
.
Source Code
이 Tutorial의 코드는 아래에서 받을 수 있다.
Download Sample Code
.
Aug 06
alonesiphone http, iphone, Mobile, Mobile Orchard, NSHTTPURLRespones,NSURLRequest
iPhone에서 http request/response는 아주 쉽고 여러 가지 용도로 잘 사용할 수 있게 제공되어 있다.
Mobile Orchard에 보니 response 받는 Http의 header를 가져오는 것에 대해서 포스트가 있어서 포스팅한다.
답은 NSHTTPURLRespones의 allHeaderFields method를 이용하는 것이다.
Synchronous request의 코드는 아래와 같고,
2 |
NSURLRequest *request = [NSURLRequest requestWithURL: url]; |
3 |
NSHTTPURLResponse *response; |
4 |
[NSURLConnection sendSynchronousRequest: request returningResponse: &response error: nil]; |
5 |
NSDictionary *dictionary = [response allHeaderFields]; |
6 |
NSLog([dictionary description]); |
Asynchronous request는 connection:didReceiveResponse:를 이용해서 아래와 같다.
1 |
- ( void )connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { |
2 |
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response; |
3 |
NSDictionary *dictionary = [httpResponse allHeaderFields]; |
4 |
NSLog([dictionary description]); |
Ref: Accessing HTTP Headers From An NSURLRequest