void UIImageFromURL( NSURL * URL, void (^imageBlock)(UIImage * image), void (^errorBlock)(void) ) { dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^(void) { NSData * data = [[NSData alloc] initWithContentsOfURL:URL]; UIImage * image = [[UIImage alloc] initWithData:data]; dispatch_async( dispatch_get_main_queue(), ^(void){ if( image != nil ) { imageBlock( image ); } else { errorBlock(); } }); }); } #import <UIKit/UIKit.h> @interface ViewController : UIViewController void UIImageFromURL( NSURL * URL, void (^imageBlock)(UIImage * image), void (^errorBlock)(void) ); @end - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. UIImageFromURL( [NSURL URLWithString:@"https://t1.daumcdn.net/cfile/tistory/186A3A384EEAE04331"], ^(UIImage * image ) { [self.view addSubview:[[UIImageView alloc] initWithImage:image]]; }, ^(void){ NSLog(@"%@",@"error!"); }); } #import <UIKit/UIKit.h> @interface ViewController : UIViewController //void UIImageFromURL( NSURL * URL, void (^imageBlock)(UIImage * image), void (^errorBlock)(void) ); - (void) loadAsyncImageFromURL:(NSURL *)url imageBlock:(void (^) (UIImage *image))imageBlock errorBlock:(void(^)(void))errorBlock; @end
비동기 방식으로 이미지를 로드하는 예제들
http://developer.apple.com/library/ios/#samplecode/LazyTableImages/index.html
http://www.markj.net/iphone-asynchronous-table-image/
http://gazapps.com/wp/2011/06/29/asynchronous-images-on-ios/
http://avishek.net/blog/?p=39
위에서 사용하는 방법은 NSURLConnection을 이용해서 delegate method를 이용하는 방법을 보통 사용한다. delegate pattern은 작업 처리를 하는 객체에게 위임을하거나 비동기적으로 객체에 메소드를 호출할때 매우 유용한 방법이다. 하지만 delegate를 사용하면 delegate 메소드가 필요하게 되고 delegate 메소드 안에서 처리할 작업을 정의해 두어야 한다.
이미지를 비동기 방식으로 로드하고 비동기 방식으로 로드하면서 외부에서 그 이미지를 처리하는 메소드까지 선언해줄수 있는 방법으로 block과 GCD (grand centeral dispatch)를 이용하는 방법을 참조하였다. block은 Python이나 Ruby 등에서 사용하는 closure 개념과 비슷하다. Block은 C 레벨의 문법과 런타임 특징이다. 이것은 C의 기본 함수와 비슷하지만 실행가능한 코드를 추가할 수가 있고 stack 또는 heap 메모리를 바인딩하는 변수를 포함할 수 있다. 이러한 특징 대문에 Block은 실행되는 동안에 어떠한 행위를 위해서 데이터의 상태를 유지할 수 있는 특성을 가진다. Block에 관해서는 다시 한번 Block의 주제에 관해서 다시 포스팅을 할 예정이다. GCD는 애플에서 개발한 기술로써 멀티코어 프로세서에 최적화된 어플리케이션을 지원하기 위해서 만들어진 기술이다. GCD는 병렬처리와 쓰레드 풀을 기반한 기술이다. GCD에 대한 상세한 내용역시 다른 포스팅으로 준비 중이다. Block과 GCD를 이용하면 기존에 사용하던 방법(delegate로 처리하는 방법)과는 다르게 원하는 방법을 구현할 수 있을 것이라는 생각을 가지고 검색해서 다음 블로그를 찾을 수 있게 되었다. http://www.geekygoodness.com/2011/06/17/uiimage-from-url-simplified/ 이 블로그에서는 아주 간단한 설명만 남겨 두었지만 Block과 GCD를 이용해서 이미지를 로드하는 방법을 소스코드로 잘 표현해 주고 있다. Block은 iOS4 이상에서만 사용이 가능하다.
이 코드를 iOS에서 사용하면 다음과 같은 warning이 나타난다.
이것은 UIImageFromURL가 미리 선언되어 있지 않아서 발생하는 경고인데 .h 파일 안에 미리 선언해주면 이 경고는 사라진다.
우리는 이 코드를 좀더 Objective-C에 익숙한 메소드와 파라미터 방식으로 변경하고 싶다고 생각했다. Objective-C의 메소드 선언 방법은 개발할때 파라미터에 대한 이름과 타입을 참조하는데 더 유용하기 때문이다. 그래서 이 코드를 다음과 같이 변경하여 인스턴스 메소드로 만들어서 사용할 수 있다.
- (void) loadAsyncImageFromURL:(NSURL *)url imageBlock:(void (^) (UIImage *image))imageBlock errorBlock:(void(^)(void))errorBlock
{
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^(void)
{
NSData * data = [[NSData alloc] initWithContentsOfURL:url];
UIImage * image = [[UIImage alloc] initWithData:data];
dispatch_async( dispatch_get_main_queue(), ^(void){
if( image != nil )
{
imageBlock( image );
} else {
errorBlock();
}
});
});
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self loadAsyncImageFromURL:[NSURLURLWithString:@"https://t1.daumcdn.net/cfile/tistory/1349CD374EA43DFB2E"]
imageBlock:^(UIImage *image){
[self.view addSubview:[[UIImageView alloc] initWithImage:image]];
}
errorBlock:^(void){
NSLog(@"%@", @"error!");
}];
// UIImageFromURL( [NSURL URLWithString:@"https://t1.daumcdn.net/cfile/tistory/186A3A384EEAE04331"], ^( UIImage * image )
// {
// [self.view addSubview:[[UIImageView alloc] initWithImage:image]];
// }, ^(void){
// NSLog(@"%@",@"error!");
// });
}
이 방법을 이용해서 테이블에 이미지를 비동기 방식으로 로드하는 예제를 작성하면 다음과 같이 될 것이다. 간단하게 테이블에 URL 문자열을 가지는 items 배열을 가지고 사용하였지만, 실제 사용할때는 이 데이터 역시 json이나 xml에서 받아와서 만들 것으로 예상이 된다. tableView:cellForRowAtIndexPath: 메소드에서 cell의 작업을 할때 우리는 비동기 방식으로 처리하는 이 코드로 작업을 처리할 수 있다.
(이 예제는 정말 단순하고 간단한 예제 이다. 더욱 좋은 코드를 만들기 위한 방법을 이 포스트에서는 소개하지 않는다.)
- (void)viewDidLoad
{
[super viewDidLoad];
items = [[NSArray alloc] initWithObjects:@"https://t1.daumcdn.net/cfile/tistory/186A3A384EEAE04331",
@"https://t1.daumcdn.net/cfile/tistory/186A3A384EEAE04331",
@"https://t1.daumcdn.net/cfile/tistory/186A3A384EEAE04331",
@"https://t1.daumcdn.net/cfile/tistory/186A3A384EEAE04331",
@"https://t1.daumcdn.net/cfile/tistory/186A3A384EEAE04331",
@"https://t1.daumcdn.net/cfile/tistory/186A3A384EEAE04331",
@"https://t1.daumcdn.net/cfile/tistory/186A3A384EEAE04331",
nil];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:CellIdentifier];
}
// Configure the cell...
[self loadAsyncImageFromURL:[NSURL URLWithString:[items objectAtIndex:indexPath.row]]
imageBlock:^(UIImage *image){
[[cell.contentView viewWithTag:999+indexPath.row] removeFromSuperview];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(04.0f, .0f, 44.0f, 44.0f);
imageView.tag = 999+indexPath.row;
[cell.contentView addSubview:imageView];
}
errorBlock:^(void){
NSLog(@"%@", @"error!");
}];
cell.textLabel.text = [items objectAtIndex:indexPath.row];
return cell;
}
참조 원문 : http://www.geekygoodness.com/2011/06/17/uiimage-from-url-simplified/
코드의 저작권은 http://www.geekygoodness.com 에 있기 때문에 코드 사용시 원 저작권자에게 사용 요청을 받기 바랍니다.
'iOS' 카테고리의 다른 글
맥/iOS용 tcp/udp 라이브러리 CocoaAsyncSocket (0) | 2012.08.29 |
---|---|
iOS5에서 NSJSONSerialization을 사용해서 JSON 다루기 예제 (0) | 2012.08.28 |
UIActivityIndicator – whilst loading map pins in background thread. (0) | 2012.08.27 |
UIProgressHUD / 어플 실행 및 , 데이터 호출시 "로딩중" 메세지처리 (0) | 2012.08.27 |
aes-128을 사용한 app과 server의 통신 (1) | 2012.08.26 |