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를 가지고 있다.
@protocol HttpManagerDelegate;
@interface HttpManager : NSObject {
id delegate;
NSMutableData *receivedData;
}
@property (nonatomic, assign) id delegate;
@property (nonatomic, retain) NSMutableData *receivedData;
.
HttpManagerDelegate protocol
HttpManagerDelegate protocol은 http request 시 request가 완료되었을 때와 실패했을 때 callback 되는 method들을 정의하고 있다. 그 외 request 시 callback 되는 NSURLConnectionDelegate의 connection method들은 내부적으로 처리했다.
@protocol HttpManagerDelegate
-(void)connectionDidFail:(HttpManager*)aHttpManager;
-(void)connectionDidFinish:(HttpManager*)aHttpManager;
.
[HttpManager initWithUrl: delegate:]
HttpManager를 initWithUrl로 init 하면 바로 주어진 url의 loading을 시작한다. 즉, url에 대해서 NSURLRequest를 만들고, NSURLConnection 생성해서 loading을 시작한다. 여기서 NSString의 URL을 [NSString stringByAddingPercentEscapesUsingEncoding:]에 NSUTF8StringEncoding을 지정해서 encoding하는 것을 잊지 말아야 한다. 공백이나 특수 문자 등을 ‘%’를 써서 encoding 해준다.
-(id)initWithUrl:(NSString*)aURL delegate:(id)aDelegate {
if( self = [super init] ) {
// delegate
self.delegate = aDelegate;
// URL string을 아래와 같이 %가 필요한 곳에 붙여주는 encoding 해줘야한다.
NSString *escapedUrl = [aURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
// create the request
NSURLRequest *aRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:escapedUrl]
cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
// create the connection with the request
// and start loading the data
NSURLConnection *aConnection=[[NSURLConnection alloc] initWithRequest:aRequest delegate:self];
if (aConnection) {
// Create the NSMutableData that will hold
// the received data
// receivedData is declared as a method instance elsewhere
receivedData = [[NSMutableData data] retain];
} else {
// inform the user that the download could not be made
// [todo] error
}
}
return self;
}
.
[HttpManager connectionDidFinishLoading:]
HttpManager의 다른 method들은 간단하며 HttpManagerDelegate를 adopt 한 caller의 해당 method를 불러주기 위해 caller가 해당 method를 가지고 있는지 체크하는 코드를 보라고 connectionDidFinishLoading method 코드를 보여준다. Caller의 connectionDidFinishLoading method가 불리면 Caller는 HttpManager의 receivedData를 받아서 사용하면 된다.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if( [self.delegate respondsToSelector:@selector(connectionDidFail:)]) {
[self.delegate connectionDidFinish:self];
}
[connection release];
if( receivedData != nil) {
[receivedData release];
receivedData = nil;
}
}
.
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해서 아래와 같다.
#import
#import "HttpManager.h"
@interface URLLoadingSystem_imageAppDelegate : NSObject {
UIWindow *window;
UIImageView *imageView;
UIActivityIndicatorView *indicator;
HttpManager *httpManager;
NSMutableData *receivedData;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) UIImageView *imageView;
-(void)getImageFrom:(NSString*)url;
@end
.
UIApplicationDelegate의 applicationDidFinishLaunching
위에서 설명한 것과 같이 UIImageView를 생성해서 UIWindow에 add하고 UIActivityIndicatorView를 생성해서 UIImageView에 add 후 animation을 시작하고 HttpManager를 picasa url로 init해서 URL Loading을 시작한다.
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Override point for customization after application launch
// create UIImageView
imageView = [[UIImageView alloc] initWithFrame:window.frame];
[window addSubview:imageView];
// image를 받을 때까지 indicator를 동작시킨다.
indicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake( window.frame.size.width/2 - 20, window.frame.size.height/2-20, 40, 40)];
indicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
[imageView addSubview:indicator];
[indicator startAnimating];
// 아래 url에서 이미지를 가져와서 UIImageView에 보여준다.
[self getImageFrom:@"http://lh4.ggpht.com/_85hIOLhClFE/SpAB03RUZtI/AAAAAAAAFgs/VdhbDuH8riQ/sample.png"];
[window makeKeyAndVisible];
}
-(void)getImageFrom:(NSString*)url {
if( httpManager ) {
[httpManager release];
httpManager = nil;
}
httpManager = [[HttpManager alloc] initWithUrl:url delegate:self];
}
.
HttpManagerDelegate의 connectionDidFinish를 adopt
connectionDidFinish: 는 URL Loading이 완료되었을 때 callback 된다. 여기서 HttpManager의 receivedData를 가져와서 아래와 같이 UIImage를 생성해서 UIImageView에 넣어주면 완료된다.
#pragma mark HttpManagerDelegate
-(void)connectionDidFinish:(HttpManager*)aHttpManager {
[indicator stopAnimating];
receivedData = httpManager.receivedData;
imageView.image = [[UIImage alloc] initWithData:receivedData];
}
.
Http Request Fail 처리
HttpManagerDelegate의 connectionDidFail은 Http Request가 실패했을 때 callback 된다. 아래와 같이 사용자에게 실패했다는 메시지를 UIAlertView로 보여준다.
-(void)connectionDidFail:(HttpManager*)aHttpManager {
[indicator stopAnimating];
UIAlertView *alertView = [[[UIAlertView alloc] initWithTitle:@"Fail" message:@"Couldn't connect" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil, nil] autorelease];
[alertView show];
}
.
Source Code
이 Tutorial의 코드는 아래에서 받을 수 있다.
.
Ref 1. URL Loading System