출처 :http://alones.kr/tag/nsurlrequest


[iPhone][Tutorial #3] URL Loading System – Http로 이미지를 받아서 보이기 (HttpManager 이용)

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에서 실행시킨 모습은 아래와 같다 (싱가폴에서 찍은 사진이다. ㅋ).

그림 9 by you.

.

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;
02  
03 @interface HttpManager : NSObject {
04  
05     id  delegate;
06  
07     NSMutableData *receivedData;
08 }
09  
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
2  
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 {
02  
03     if( self = [super init] ) {
04  
05         // delegate
06         self.delegate = aDelegate;
07  
08         // URL string을 아래와 같이 %가 필요한 곳에 붙여주는 encoding 해줘야한다.
09         NSString *escapedUrl = [aURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
10  
11         // create the request
12         NSURLRequest *aRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:escapedUrl]
13                                 cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
14         // create the connection with the request
15         // and start loading the data
16         NSURLConnection *aConnection=[[NSURLConnection alloc] initWithRequest:aRequest delegate:self];
17         if (aConnection) {
18             // Create the NSMutableData that will hold
19             // the received data
20             // receivedData is declared as a method instance elsewhere
21             receivedData = [[NSMutableData data] retain];
22         else {
23             // inform the user that the download could not be made
24             // [todo] error
25         }
26     }
27  
28     return self;
29 }

.
[HttpManager connectionDidFinishLoading:]

HttpManager의 다른 method들은 간단하며 HttpManagerDelegate를 adopt 한 caller의 해당 method를 불러주기 위해 caller가 해당 method를 가지고 있는지 체크하는 코드를 보라고 connectionDidFinishLoading method 코드를 보여준다. Caller의 connectionDidFinishLoading method가 불리면 Caller는 HttpManager의 receivedData를 받아서 사용하면 된다.

01 - (void)connectionDidFinishLoading:(NSURLConnection *)connection {
02  
03     if( [self.delegate respondsToSelector:@selector(connectionDidFail:)]) {
04         [self.delegate connectionDidFinish:self];
05     }
06  
07     [connection release];
08     if( receivedData != nil) {
09         [receivedData release];
10         receivedData = nil;
11     }
12 }

.

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해서 아래와 같다.

01 #import
02 #import "HttpManager.h"
03  
04 @interface URLLoadingSystem_imageAppDelegate : NSObject  {
05     UIWindow *window;
06  
07     UIImageView *imageView;
08     UIActivityIndicatorView *indicator;
09  
10     HttpManager *httpManager;
11     NSMutableData *receivedData;
12 }
13  
14 @property (nonatomic, retain) IBOutlet UIWindow *window;
15 @property (nonatomic, retain) UIImageView *imageView;
16  
17 -(void)getImageFrom:(NSString*)url;
18  
19 @end

.

UIApplicationDelegate의 applicationDidFinishLaunching

위에서 설명한 것과 같이 UIImageView를 생성해서 UIWindow에 add하고 UIActivityIndicatorView를 생성해서 UIImageView에 add 후 animation을 시작하고 HttpManager를 picasa url로 init해서 URL Loading을  시작한다.

01 - (void)applicationDidFinishLaunching:(UIApplication *)application {   
02  
03     // Override point for customization after application launch
04     // create UIImageView
05     imageView = [[UIImageView alloc] initWithFrame:window.frame];
06     [window addSubview:imageView];
07  
08     // image를 받을 때까지 indicator를 동작시킨다.
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];
13  
14     // 아래 url에서 이미지를 가져와서 UIImageView에 보여준다.
16  
17     [window makeKeyAndVisible];
18 }
19  
20 -(void)getImageFrom:(NSString*)url {
21     if( httpManager ) {
22         [httpManager release];
23         httpManager = nil;
24     }
25  
26     httpManager = [[HttpManager alloc] initWithUrl:url delegate:self];
27 }

.

HttpManagerDelegate의 connectionDidFinish를 adopt

connectionDidFinish: 는 URL Loading이 완료되었을 때 callback 된다. 여기서 HttpManager의 receivedData를 가져와서 아래와 같이 UIImage를 생성해서 UIImageView에 넣어주면 완료된다.

1 #pragma mark HttpManagerDelegate
2 -(void)connectionDidFinish:(HttpManager*)aHttpManager {
3     [indicator stopAnimating];
4  
5     receivedData = httpManager.receivedData;
6     imageView.image = [[UIImage alloc] initWithData:receivedData];
7 }

.

Http Request Fail 처리

HttpManagerDelegate의 connectionDidFail은 Http Request가 실패했을 때 callback 된다. 아래와 같이 사용자에게 실패했다는 메시지를 UIAlertView로 보여준다.

1 -(void)connectionDidFail:(HttpManager*)aHttpManager {
2     [indicator stopAnimating];
3  
4     UIAlertView *alertView = [[[UIAlertView alloc] initWithTitle:@"Fail" message:@"Couldn't connect"delegate:self cancelButtonTitle:@"OK"otherButtonTitles:nil, nil] autorelease];
5     [alertView show];
6 }

.

Source Code

이 Tutorial의 코드는 아래에서 받을 수 있다.

Download Sample Code

.


[iPhone] NSURLRequest로 받은 response에서 Http header를 가져오기 – Accessing HTTP Headers From An NSURLRequest

  0 Comments and 0 Reactions

iPhone에서 http request/response는 아주 쉽고 여러 가지 용도로 잘 사용할 수 있게 제공되어 있다.

Mobile Orchard에 보니 response 받는 Http의 header를 가져오는 것에 대해서 포스트가 있어서 포스팅한다.

답은 NSHTTPURLRespones의 allHeaderFields method를 이용하는 것이다.

Synchronous request의 코드는 아래와 같고,

1 NSURL *url = [NSURL URLWithString:@"http://www.mobileorchard.com"];
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]);
5 }

Ref: Accessing HTTP Headers From An NSURLRequest


Posted by 엔귤