본문 바로가기

iPhone Dev

내 입맛에 맞는 AsyncImageView

반응형
인터넷에 떠도는 AsyncImageView를 내 입맛에 맛도록 수정해서 사용하고 있다.
상황에 따라 여러가지 요구사항이 있는데 인터넷에 배포되는 소스는 단순히 기본적인 기능만을 구현해 놓았기 때문에 부분적인 수정이 불가피하다.
누군가 처음 공부하는 사람들에게 작은 도움이나마 될수 있을까 생각해보며 블로깅 한다



//
//  AsyncImageView.h
//  Postcard
//
//  Created by markj on 2/18/09.
//  Copyright 2009 Mark Johnson. You have permission to copy parts of this code into your own projects for any use.
//  www.markj.net
//

#import 


@interface AsyncImageView : UIView {
	//could instead be a subclass of UIImageView instead of UIView, depending on what other features you want to 
	// to build into this class?

	NSURLConnection* connection; //keep a reference to the connection so we can cancel download in dealloc
	NSMutableData* data; //keep reference to the data so we can collect it as it downloads
	//but where is the UIImage reference? We keep it in self.subviews - no need to re-code what we have in the parent class
    
    NSURL *img_path;
    
    id target;
    SEL action;
}
- (void)loadImageFromURL:(NSURL*)url addTarget:(id)onTarget addAction:(SEL)onAction;
- (void)loadImageFromURL:(NSURL*)url;
- (UIView*)getCachedImage:(NSString*)img_url;
@end






//
//  AsyncImageView.m
//  Postcard
//
//  Created by markj on 2/18/09.
//  Copyright 2009 Mark Johnson. You have permission to copy parts of this code into your own projects for any use.
//  www.markj.net
//

#import "AsyncImageView.h"


// This class demonstrates how the URL loading system can be used to make a UIView subclass
// that can download and display an image asynchronously so that the app doesn't block or freeze
// while the image is downloading. It works fine in a UITableView or other cases where there
// are multiple images being downloaded and displayed all at the same time. 

@implementation AsyncImageView

- (void)dealloc {
	[connection cancel]; //in case the URL is still downloading
	[connection release];
	[data release]; 
    [img_path release];
    [super dealloc];
}

- (NSString *)applicationDocumentsDirectory {
	
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
    return basePath;
}

- (NSString *) getImageFilePath:(NSString *)imageFileName {
	
	// get the documents directory:
	NSString *documentsDirectory = [self applicationDocumentsDirectory];
	BOOL isDirectory = YES;
	
	// validation check -  make a saving directory to write the image data to using the documents directory:
	NSString *imageDirectory = [NSString stringWithFormat:@"%@/saveData/image", documentsDirectory];
	NSString *imageFileFullPath = [NSString stringWithFormat:@"%@/%@", imageDirectory, imageFileName];
    //	NSLog(@"%@", imageFileFullPath);
	if(![[NSFileManager defaultManager] fileExistsAtPath:imageDirectory isDirectory:&isDirectory]) {
		//if(![[NSFileManager defaultManager] createDirectoryAtPath:imageDirectory attributes:nil]) {
		if(![[NSFileManager defaultManager] createDirectoryAtPath:imageDirectory withIntermediateDirectories:YES attributes:nil error:nil]){
			imageFileFullPath = nil;
		} else {
		}
		
	}
	
	return imageFileFullPath;
}

- (NSString *)getImageFileName:(NSString *)imageURL { 
	
	NSString *imageFileName = nil;
	
	if ([imageURL length] > 0) {
		imageFileName = [imageURL stringByReplacingOccurrencesOfString:@"http://" withString:@"/"];
		NSString *imagePathComponent = [imageFileName stringByDeletingLastPathComponent];	
		
		imagePathComponent = [NSString stringWithFormat:@"%@/", imagePathComponent];
		imageFileName = [imageFileName stringByReplacingOccurrencesOfString:imagePathComponent withString:@""];
		
	} 
	
	return imageFileName;
}




- (void) cacheImage
{
	//	generate a unique path to a resource representing the image you want
	NSString *filename = [self getImageFileName:[img_path absoluteString]];
	NSString *uniquePath = [self getImageFilePath:filename];
	
	if (![[NSFileManager defaultManager] fileExistsAtPath:uniquePath]) {
		UIImage *image = [[UIImage alloc] initWithData:data];
        
		if(NO == [UIImagePNGRepresentation(image) writeToFile:uniquePath atomically:YES]) {
			NSLog(@" --- Unable to store image file : %@ --- ", uniquePath);
		} else {
			NSLog(@" --- image file : %@ is saved --- ", uniquePath);
		}
		[image release];
	}
}

- (UIView*)getCachedImage:(NSString*)img_url
{
   
	NSString *filename = [self getImageFileName:img_url];
	NSString *uniquePath = [self getImageFilePath:filename];
    
	if ([[NSFileManager defaultManager] fileExistsAtPath:uniquePath]) {
		UIImage *image = [UIImage imageWithContentsOfFile:uniquePath];

        if (image) {
            if ([[self subviews] count]>0) {
                //then this must be another image, the old one is still in subviews
                [[[self subviews] objectAtIndex:0] removeFromSuperview]; //so remove it (releases it also)
            }
            UIImageView* imageView = [[[UIImageView alloc] initWithImage:image] autorelease];
            imageView.contentMode = UIViewContentModeScaleToFill;
            imageView.autoresizingMask = ( UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight );
            [self addSubview:imageView];
            imageView.frame = self.bounds;
            [imageView setNeedsLayout];
            [self setNeedsLayout];
            
            return self;
        }
	}
    
    return nil;
}

- (void)loadImageFromURL:(NSURL*)url addTarget:(id)onTarget addAction:(SEL)onAction
{
	if (connection!=nil) { [connection release]; } //in case we are downloading a 2nd image
	if (data!=nil) { [data release]; }
	NSLog(@"img url : %@", url);
    img_path = [url retain];

    target = onTarget;
    action = onAction;

    NSURLRequest* request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
	connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; //notice how delegate set to self object
    
}


- (void)loadImageFromURL:(NSURL*)url {
	if (connection!=nil) { [connection release]; } //in case we are downloading a 2nd image
	if (data!=nil) { [data release]; }
	NSLog(@"img url : %@", url);
    img_path = [url retain];
    
	NSURLRequest* request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
	connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; //notice how delegate set to self object
	//TODO error handling, what if connection is nil?
}


//the URL connection calls this repeatedly as data arrives
- (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)incrementalData {
	if (data==nil) { data = [[NSMutableData alloc] initWithCapacity:2048]; } 
	[data appendData:incrementalData];
}

//the URL connection calls this once all the data has downloaded
- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection {
	//so self data now has the complete image 
	[connection release];
	connection=nil;
	if ([[self subviews] count]>0) {
		//then this must be another image, the old one is still in subviews
		[[[self subviews] objectAtIndex:0] removeFromSuperview]; //so remove it (releases it also)
	}
	
	//make an image view for the image
	UIImageView* imageView = [[[UIImageView alloc] initWithImage:[UIImage imageWithData:data]] autorelease];
	//make sizing choices based on your needs, experiment with these. maybe not all the calls below are needed.
//	imageView.contentMode = UIViewContentModeScaleAspectFit;
    imageView.contentMode = UIViewContentModeScaleToFill;
	imageView.autoresizingMask = ( UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight );
	[self addSubview:imageView];
	imageView.frame = self.bounds;
	
	
	[imageView setNeedsLayout];
	[self setNeedsLayout];
    
    [self cacheImage];
    
    if (target && [target respondsToSelector:action]) {
        [target performSelector:action withObject:self];
    }

	[data release]; //don't need this any more, its in the UIImageView now
	data=nil;
}


@end







수정 내용
1. 캐쉬를 이용하여 로드가 완료된 이미지를 캐쉬에 저장, 수시로 꺼내 사용할 수 있도록 하였음.
2. 이미지 다운로드 시기를 알고 싶은 경우 selector를 이용하여 완료시점에 원하는 selector를 호출할 수 있도록 추가
반응형