Load image to a tableView from URL iphone sdk - iphone

I have tableView and need to load image from URL. I have an array that contains the URLs of images and when the page loads I need to load all the images into the tableview. Note that, not from a single URL, have an array with different URLs. How can I implement that? Please help
Thanks.

You can use GCD to load images in background thread, like this:
//get a dispatch queue
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//this will start the image loading in bg
dispatch_async(concurrentQueue, ^{
NSData *image = [[NSData alloc] initWithContentsOfURL:imageURL];
//this will set the image when loading is finished
dispatch_async(dispatch_get_main_queue(), ^{
imageView.image = [UIImage imageWithData:image];
});
});
Hi. But you probably need to add a dispatch_release(concurrentQueue); to be sure no leak. – Franck Aug 25 at 19:43

You can use Lazy Loading when you want to download Images from internet
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//All you reusable cell implementation here.
//Since your Images sizes differ. Keep a custom Imageview
if(![imagesForCategories containsObject:indexPath])
{
customImageView.image = [UIImage imageNamed:#"default-image.png"];
NSMutableArray *arr = [[NSArray alloc] initWithObjects:[imageUrlArray objectAtIndex:indexPath.row],indexPath, nil];
[self performSelectorInBackground:#selector(loadImageInBackground:) withObject:arr];
[arr release];
}
return cell;
}
- (void) loadImageInBackground:(NSArray *)urlAndTagReference
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSURL *imgUrl=[[NSURL alloc] initWithString:[urlAndTagReference objectAtIndex:0]];
NSData *imgData = [NSData dataWithContentsOfURL:imgUrl];
UIImage *img = [UIImage imageWithData:imgData];
[imgUrl release];
NSMutableArray *arr = [[NSMutableArray alloc ] initWithObjects:img,[urlAndTagReference objectAtIndex:1], nil ];
[self performSelectorOnMainThread:#selector(assignImageToImageView:) withObject:arr waitUntilDone:YES];
[arr release];
[pool release];
}
- (void) assignImageToImageView:(NSMutableArray *)imgAndTagReference
{
[imagesForCategories addObject:[imgAndTagReference objectAtIndex:1]];
UITableViewCell *cell = [celebCategoryTableView cellForRowAtIndexPath:[imgAndTagReference objectAtIndex:1]];
UIImageView *profilePic = (UIImageView *)[cell.contentView viewWithTag:20];
profilePic.image = [imgAndTagReference objectAtIndex:0];
}

You can use SDWebImage which permits very easy and speed loading of images in UITableView.
https://github.com/rs/SDWebImage

Try this code,imagearray contains urls of image
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString: [imagearray objectAtIndex:row]]];
UIImage* image = [[UIImage alloc] initWithData:imageData];
cell.imageView.image =image;
return cell;
}

You need to create your custom cell for lazy loading. This will allow you to download images correctly and without freezing. Here is nice example how to do this:
Asynch image loading

With afnetworki, it is too easy.
//afnetworking
#import "UIImageView+AFNetworking.h"
[cell.iboImageView setImageWithURL:[NSURL URLWithString:server.imagen] placeholderImage:[UIImage imageNamed:#"qhacer_logo.png"]];

Related

Loading images in background to optimize the loading in ios

I am trying to optimize the load in my application, in fact, I have a lot of images that loaded in my application, and I spend a lot of time waiting for a view controller to open, especially the first initial view which includes a lot of images.
I took a look at apple sample
but I cannot re-work the whole application, what I want is just to tell me specifically what should I do?, I implement?
in the tableview, where the cell is implemented cellforrowatindexpath:
NSURL *imageURL = ......;
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *imageLoad;
imageLoad = [[UIImage alloc] initWithData:imageData];
imageView.image = imageLoad;
could I do something?
thank you for your help!
Try this code:
dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(q, ^{
/* Fetch the image from the server... */
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[UIImage alloc] initWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
/* This is the main thread again, where we set the tableView's image to
be what we just fetched. */
cell.imgview.image = img;
});
});
Yes, you can add placeholder image to it.
It will not slow down the scrolling and will load image accordingly with time.
Also import this file UIImageView+WebCache.m and MapKit Framework
Here is the link to download the files.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
UIImageview* iV = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 50, 50)];
[iV setImageWithURL:[NSURL URLWithString:url] placeholderImage:[UIImage imageNamed:#"image_placeholder.gif"]];
[cell.contentView addSubview:iV];
[iV release];
}
Just clean, build and run.
To enable the app while getting the images from server and disable block while loading the images try to use UIImageView+AFNetworking library to load the image from server asynchronously AFNetworking
NSString *imageUrl = [[dict objectForKey:#"photo"] objectForKey:#"url"];
UIImageView *myImage = [[UIImageView alloc] init];
[myImage setImageWithURL:[NSURL URLWithString:imageUrl] placeholderImage:[UIImage imageNamed:#"PlaceHolder.png"]];
Just add this library and include the UIImageView+AFNetworking so you can use the new UIImageView Category imageWithUrl
Take a look at this control:
https://github.com/nicklockwood/AsyncImageView
It's very easy to implement (only 1 header file) and will suit your needs just fine.
Using this control:
Instead of declaring:
NSURL *imageURL = ......;
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *imageLoad;
imageLoad = [[UIImage alloc] initWithData:imageData];
imageView.image = imageLoad;
Use:
NSURL *imageURL = ......;
imageView.imageURL = imageURL;
you can check this tutorial on NSOperationQueue and this on GCD doing exactly same. Also you can try using:
// Block variable to be assigned in block.
__block NSData *imageData;
dispatch_queue_t backgroundQueue = dispatch_queue_create("com.razeware.imagegrabber.bgqueue", NULL);
// Dispatch a background thread for download
dispatch_async(backgroundQueue, ^(void) {
imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *imageLoad;
imageLoad = [[UIImage alloc] initWithData:imageData];
// Update UI on main thread
dispatch_async(dispatch_get_main_queue(), ^(void) {
imageView.image = imageLoad;
});
});
You can try something like this!....
dispatch_queue_t checkInQueueForPostImage = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(checkInQueueForPostImage, ^{
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:postAndCheckInDetails.postImageURL]]];
dispatch_sync(dispatch_get_main_queue(), ^{
if (image!=nil) {
[uploadImage setImage:image];
}
[cell setNeedsLayout];
});
});
Here is a slightly modified approach of Ramu Pasupoletis answer. I added the
__block
modifier to make the var img visible inside the block called on the main thread. Here is the complete method definition which I use in
-(UITableViewCell*)cellforRowAtIndexPath:(UIIndexPath*)indexPath;
for fetching the thumbnails lazily. I also added placeholders there for the cells UIImageViews.
//lazy loading of thumbnails for images in cell via bg thread
-(void)loadImageForCell:(CustomEditTableViewCell*)theCell withFilepath: (NSString*)filepath{
dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(q, ^{
UIImage (__block *img) = [UIImage imageWithContentsOfFile:filepath];
UIImage *thumbnail = [[GlobalFunctions sharedGlobalFunctions] imageOfSize:CGSizeMake(40, 40) fromImage:img];
dispatch_async(dispatch_get_main_queue(), ^{
theCell.imageView.image = thumbnail;
});
});
}
Use IDAsyncImageView.h
//////////////////////////////////////
IDAsyncImageView.h
/////////////////////////////////////
#interface IDAsyncImageView : NSObject
#property (nonatomic, strong) NSCache *cache;
+ (instancetype)instance;
- (void)loadImageView:(UIImageView*)imageView withURLString:(NSString *)urlString;
#end
//////////////////////////////////////
IDAsyncImageView.m
/////////////////////////////////////
#import "IDAsyncImageView.h"
#implementation IDAsyncImageView
+ (instancetype)instance
{
static IDAsyncImageView *_instance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc] init];
});
return _instance;
}
- (instancetype)init
{
self = [super init];
if (self) {
self.cache = [[NSCache alloc] init];
}
return self;
}
- (void)loadImageView:(UIImageView*)imageView withURLString:(NSString *)urlString
{
UIActivityIndicatorView* activityView;
activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityView.hidesWhenStopped = YES;
activityView.center = CGPointMake(imageView.bounds.size.width / 2.0f, imageView.bounds.size.height / 2.0f);
activityView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
[imageView addSubview:activityView];
[activityView startAnimating];
UIImage* imageLoad = [self.cache objectForKey:urlString];
if (nil != imageLoad) {
imageView.image = imageLoad;
[activityView removeFromSuperview];
}
else {
// Block variable to be assigned in block.
__block NSData *imageData;
// Dispatch a background thread for download
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]];
UIImage* imageLoad = [[UIImage alloc] initWithData:imageData];
// Update UI on main thread
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self.cache setObject:imageLoad forKey:urlString];
imageView.image = imageLoad;
[activityView removeFromSuperview];
});
});
}
}
//////////////////////////////////////
ViewController.m
//////////////////////////////////////
- (void)viewDidLoad {
[super viewDidLoad];
[[IDAsyncImageView instance] loadImageView:myImageView withURLString:aUrl];
}
You can use async imageview.
- (void) loadImageFromURL:(NSURL*)url placeholderImage:(UIImage*)placeholder cachingKey:(NSString*)key {
self.imageURL = url;
self.image = placeholder;
NSData *cachedData = [FTWCache objectForKey:key];
if (cachedData) {
self.imageURL = nil;
self.image = [UIImage imageWithData:cachedData];
return;
}
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *imageFromData = [UIImage imageWithData:data];
[FTWCache setObject:data forKey:key];
if (imageFromData) {
if ([self.imageURL.absoluteString isEqualToString:url.absoluteString]) {
dispatch_sync(dispatch_get_main_queue(), ^{
self.image = imageFromData;
});
} else {
// NSLog(#"urls are not the same, bailing out!");
}
}
self.imageURL = nil;
});
}
Take a look at this link.You will have an idea on using async imageview.

UIImage not working properly?

i m trying load UIImages from server asynchronously in UITableViewCell.
My code worked fine in simulator but not on device. My code as follows,
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
IScopeCustomTableCell *cell = (IScopeCustomTableCell *)[tableView dequeueReusableCellWithIdentifier:CellClassName];
if (!cell){
NSArray *topLevelItems = [cellLoader instantiateWithOwner:self options:nil];
cell = [topLevelItems objectAtIndex:0];
}
cell.delegate = self;
cell.videoTitle.text = [[videoDataArray objectAtIndex:indexPath.row] objectForKey:#"VideoTitle"];
cell.videoLink = [[videoDataArray objectAtIndex:indexPath.row] objectForKey:#"VideoLink"];
cell.videoThumbnailImageLink = [[videoDataArray objectAtIndex:indexPath.row] objectForKey:#"VideoThumbnail"];
cell.videoThumbnail.tag = indexPath.row;
cell.tag = indexPath.row;
[cell.activityIndicator startAnimating];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(loadImage:)
object:cell];
[queue addOperation:operation];
return cell;
}
- (void)loadImage:(IScopeCustomTableCell *)cell {
NSLog(#"Image link :- %#", cell.videoThumbnailImageLink);
//NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:cell.videoThumbnailImageLink]];
NSData* imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:cell.videoThumbnailImageLink]];
UIImage* image = [UIImage imageWithData:imageData];
cell.videoThumbnail.image = image;
[cell.activityIndicator stopAnimating];
[cell.activityIndicator removeFromSuperview];
//[self performSelectorOnMainThread:#selector(displayImage:) withObject:image waitUntilDone:NO];
}
The above code fine on simulator but not on device, becoz, UIImage *image get (0X0)null in even though NSData loadImage method containing appropriate data.
What you are doing is not the best way to do it as it will create many autoreleased objects and will increase the size of your app and also you are not releasing your operation... so first of all release your operation after [queue addOperation:operation];
and use this code instead for getting the image data and storing it in your image...
NSData* data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:cell.videoThumbnailImageLink]]];
UIImage* img = [[UIImage alloc] initWithData:data];
[data release];
cell.videoThumbnail.image = image;
[img release];
hoping this sorts your problem..
This link containing image cache code and it worked properly exact that i would like.
https://github.com/jakemarsh/JMImageCache

upload image from url in scroll view

I have array of image in scroll view. I want to upload bigger image from url when i tap on image.
for example i tap on image"page-001.jpg" then check image data and then upload bigger image on image view and get back option so that go back to previous image view.
try this
NSMutableArray *arr = [[NSArray alloc] initWithObjects:imageURL,imageView.tag, nil];
[self performSelectorInBackground:#selector(loadImageInBackground:) withObject:arr];
- (void) loadImageInBackground:(NSArray *)urlAndTagReference
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Retrieve the remote image. Retrieve the imgURL from the passed in array
NSURL *imgUrl=[[NSURL alloc] initWithString:[urlAndTagReference objectAtIndex:0]];
NSData *imgData = [NSData dataWithContentsOfURL:imgUrl];
UIImage *img = [UIImage imageWithData:imgData];
[imgUrl release];
// Create an array with the URL and imageView tag to
// reference the correct imageView in background thread.
NSMutableArray *arr = [[NSMutableArray alloc ] initWithObjects:img,[urlAndTagReference objectAtIndex:1], nil ];
// Image retrieved, call main thread method to update image, passing it the downloaded UIImage
[self performSelectorOnMainThread:#selector(assignImageToImageView:) withObject:arr waitUntilDone:YES];
[arr release];
[pool release];
}
- (void) assignImageToImageView:(NSMutableArray *)imgAndTagReference
{
UIImageView *profilePic = (UIImageView *)[cell.contentView viewWithTag:20];
imageView.image = [imgAndTagReference objectAtIndex:0];
}
You can use SDWebImage. Just add the files to your project and use
[UIImageview setImageWithURL:(NSURL*)url];
This library also manage cache, and works very well in an UITableViewCell.

releasing all cells in tableview ios iphone

i got mem leaking problem discovered with profiling in xcode. The problem it's quite easy but i can't understand how fix it:
Consider a uiviewcontroller with 2 button and a tableview.
button1=load JSON data from server and add cells to tableview then [tableview reloadData]
button2=load JSON data from another server and add cells to tableview then reload.
ok the problem is in:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
....
.....
NSURL *url = [NSURL URLWithString:stringpath];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img;
if(!data) img=[UIImage imageNamed:#"small.jpg"];
else img= [[UIImage alloc] initWithData:data];
cell.imageView.image = img;
Ok now if i start to switch with 2 button everytime i switch i got leaking from UIImage, so i think i need to "purge" (release) all cells data before reloading?
Thx
You should be releasing the img object after setting it in cell.imageView.image. I prefer to autorelease on the same line as it makes it easier for me to keep track.
UIImage *img;
if(!data) img=[UIImage imageNamed:#"small.jpg"];
else img= [[[UIImage alloc] initWithData:data] autorelease];
cell.imageView.image = img;
As mentioned in another answer, you can save yourself the pain by not using the initWithData call, but instead imageWithData.
The cells will take care of themselves.
The issue is not releasing img,plz use below
if (!data)
{
img = [UIImage imageNamed:#"small.jpg"];
cell.imageView.image = img;
}
else
{
img = [[UIImage alloc] initWithData:data];
cell.imageView.image = img;
[img release];
}
I would replace this line:
else img= [[UIImage alloc] initWithData:data];
with:
else img= [UIImage imageWithData:data];
You don't have to allocate memory for UIImage. You can perform the above implementation as follows :
NSData *data = [NSData dataWithContentsOfURL:url];
cell.imageView.image = [UIImage imageWithData: data];
Try this.

Help me on loading the images on table view using NSOperationQueue

Kindly look the below code..i found from web
- (void) loadData {
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
selector:#selector(loadDataWithOperation) object:nil];
[queue addOperation:operation];
[operation release];
}
- (void) loadDataWithOperation {
NSURL *dataURL = [NSURL URLWithString:#"http://icodeblog.com/samples/nsoperation/data.plist"];
NSArray *tmp_array = [NSArray arrayWithContentsOfURL:dataURL];
for(NSString *str in tmp_array) {
[self.array addObject:str];
}
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
[cell.textLabel setText:[self.array objectAtIndex:indexPath.row]];
return cell;
}
I have found the above code which loads the text from the web without any problem.( i mean gui is not hanging ).like wise i want to load images into the table view.for that i have wriiten the below code.
- (void) loadDataWithOperation {
NSString *Img_id, *Img_name, *DynamicImgUrl;
Img_id = xmltag.equip_id;
Img_name = xmltag.image;
DynamicImgUrl = [NSString stringWithFormat:#"http://test.com/pics/equipment/%#/%#",Img_id, Img_name];
NSURL *ImageUrl = [NSURL URLWithString:DynamicImgUrl];
//UIImage *image = [UIImage imageWithData: [NSData dataWithContentsOfURL:ImageUrl]];
NSArray *tmp_array = [NSArray arrayWithContentsOfURL:ImageUrl];
for(NSString *str in tmp_array) {
[self.array addObject:str];
}
[self.tableView performSelectorOnMainThread:#selector(reloadData) withObject:nil waitUntilDone:YES];
}
Am i correct here? how can i go with adding into the table view...
Kindly help me out...
U are seeking to display images on Tableview from URL, when u download image from url we need to consider some issues, it will freeze ur table view if u goahead with ordinary loading image.
i suggest u look at LazyLoading image
u see this link http://developer.apple.com/library/ios/#samplecode/LazyTableImages/Introduction/Intro.html
Download this sample and get to know the things