This post describes how to load an image from a remote server asynchronously in iOS, and from this post it even shows how to subclass UIImageView.
Whenever our application communicates with a server for data we usually use asynchronous calls to server from client side,so as to avoid blocking or so as to maintain thread safety, suppose say we are fetching an image from a url since we are making an asynchronous call from client side and since it is asynchronous call we can't make sure that when exactly we will get response so till that time we need to show some default image to user and once you get the actual image refresh the UIImageView with this image.
Here LoadImageAsynchronousSample demo app available to download
Algorithm:
Step 1: Subclass UIImageView and add a method to this class to load image asynchronously.
Step 2: Add a placeholder default image to this imageview initially, until you get actual image from service(url).
Step 3: Create an object of NSURLRequest so as to invoke asynchronous service call and implement NSURLConnection Methods delegate methods so as to handle response.
Step 4: Once you get response successfully from service just load that image(data) to your imageview.
LoadImageAsynchronously.h file is as below,
#import <UIKit/UIKit.h>
@interface LoadImageAsynchronously : UIImageView{
NSURLConnection *connection;
NSMutableData *data;
}
- (void)loadImageAsyncFromURL:(NSURL *)url placeholderImage:(UIImage *)placeholderImg; //method to load image asynchronously
@end
loadImageAsyncFromURL method you need to call from your class file where ever you want to load an image from a url, this method accepts 2 paramaters one is your image url from where you want to load another is placeholderImg which is to fill your image view with some local default image from your project bundle initially until and unless you get the actual image from your image url.
LoadImageAsynchronously.m file is as below,
Whenever our application communicates with a server for data we usually use asynchronous calls to server from client side,so as to avoid blocking or so as to maintain thread safety, suppose say we are fetching an image from a url since we are making an asynchronous call from client side and since it is asynchronous call we can't make sure that when exactly we will get response so till that time we need to show some default image to user and once you get the actual image refresh the UIImageView with this image.
Here LoadImageAsynchronousSample demo app available to download
Algorithm:
Step 1: Subclass UIImageView and add a method to this class to load image asynchronously.
Step 2: Add a placeholder default image to this imageview initially, until you get actual image from service(url).
Step 3: Create an object of NSURLRequest so as to invoke asynchronous service call and implement NSURLConnection Methods delegate methods so as to handle response.
Step 4: Once you get response successfully from service just load that image(data) to your imageview.
LoadImageAsynchronously.h file is as below,
#import <UIKit/UIKit.h>
@interface LoadImageAsynchronously : UIImageView{
NSURLConnection *connection;
NSMutableData *data;
}
- (void)loadImageAsyncFromURL:(NSURL *)url placeholderImage:(UIImage *)placeholderImg; //method to load image asynchronously
@end
loadImageAsyncFromURL method you need to call from your class file where ever you want to load an image from a url, this method accepts 2 paramaters one is your image url from where you want to load another is placeholderImg which is to fill your image view with some local default image from your project bundle initially until and unless you get the actual image from your image url.
LoadImageAsynchronously.m file is as below,
#import "LoadImageAsynchronously.h"
@implementation LoadImageAsynchronously
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
#pragma mark - LoadImageAsyncFromURL Method
- (void)loadImageAsyncFromURL:(NSURL *)url placeholderImage:(UIImage *)placeholderImg{
if(placeholderImg)
{
self.image=placeholderImg; //placeholderImg is a local image inside project bundle
}
NSURLRequest *request=[[NSURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:90.0];
if(connection)
{
[connection cancel];
connection=nil;
data=nil;
}
connection=[[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
}
#pragma mark - NSURLConnection Methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[data setLength:0];
}
- (void)connection:(NSURLConnection *)theConnection didReceiveData:(NSData *)incrementalData
{
if (data == nil)
data = [[NSMutableData alloc] init];
[data appendData:incrementalData];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)theConnection
{
UIImage *image=[UIImage imageWithData:data]; //image data from service(url)
if(image){
self.image=image;
}
data=nil;//so as to flush any cache data
connection=nil;//so as to flush any cache data
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(@"Connection failed: %@", [error description]);
}
and finally in your calling class just import LoadImageAsynchronously.h file and create an object of LoadImageAsynchronously class as below,
#import <UIKit/UIKit.h>
#import "LoadImageAsynchronously.h"
@interface ViewController : UIViewController
{
LoadImageAsynchronously *myImageView;
}
@end
finally pass your image url and call loadImageAsyncFromURL method of LoadImageAsynchronously class as below,
#import "ViewController.h"
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *imageURL = @"http://www.gstatic.com/webp/gallery/1.jpg";//image url
UIImage *defaultPlaceholderImg = [UIImage imageNamed:@"default_image.jpeg"];//from local bundle
myImageView=[[LoadImageAsynchronously alloc] initWithFrame:CGRectMake(20.0, 20.0, 200.0, 200.0)];
myImageView.contentMode=UIViewContentModeScaleAspectFill;
myImageView.clipsToBounds=true;
NSURL *url = [NSURL URLWithString:imageURL];
[myImageView loadImageAsyncFromURL:url placeholderImage:defaultPlaceholderImg]; //UIImageView subclass method
[self.view addSubview:myImageView];
}
@end
and thats it, hope you enjoyed the post, any pros or cons or suggestions is appreciated and accepted in advance, thank you,,,, :-)
it is getting one image asynchronously at a time, can u please help me to get bulk of images from array of url string asynchronously as UIImage.
ReplyDeleteThanks in advance.
You can use the same methods and the same class which I have mentioned in this post even for the bulk of images from the array, Create NSURLRequest objects as per your array count and assign a unique tag for every request object so that whenever the asynchronous response comes you can differentiate the response easily. Hope this helps,, :)
DeleteWhen i use you code in tableview cell it displace images but when i scroll table it delete the previous images which was already displayed
ReplyDeleteUITableView only loads and keeps the visible frame cell data in memory at any instance of time, So when ever you try to scroll the tableview make sure that how you will manage cell data in tableViews cellForRowAtIndexPath datasource method,
DeleteYou should fetch the image for the cell for a particular indexPath.row in cellForRowAtIndexPath.
Since when you scroll down your previous cell data will not be available in memory you are losing the data when you scroll back upwards, Its our responsibility to refetch/refresh the respective visible cells(indexpath.row) data again when we scroll back in cellForRowAtIndexPath.
Hope this helps,,, :)