how to load image in background in UITableCell in iphone application - iphone

I have develop an RSS application. in My table cell I am displaying images which i retrive from imge link in RSS feed and Title.
Images are loaded successfully but the problem is that it hang my application.
as there any way to load image in background.
my current code is.
int blogEntryIndex1 = [indexPath indexAtPosition: [indexPath length] -1];
imgstring=[[blogEntries objectAtIndex: blogEntryIndex1] objectForKey: #"image"];
NSURL *url = [NSURL URLWithString:imgstring];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[UIImage alloc] initWithData:data];
cell.imageView.image=[img autorelease];
any idea please, Thanks in advance...

Repost... You should also look at lazy table loading via Apple's sample code http://developer.apple.com/iphone/library/samplecode/LazyTableImages/Introduction/Intro.html
Update another example here: http://www.markj.net/iphone-asynchronous-table-image/

Well guys i have done it the code is...
- (void) loadImage:(id)object {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Get the data to pass in
NSDictionary *dict = (NSDictionary *)object;
// Get the cell and the image string
NSString *imgstring = [dict objectForKey:#"imgstring"];
MyfirstCell *cell = [dict objectForKey:#"cell"];
NSURL *url = [NSURL URLWithString:imgstring];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[UIImage alloc] initWithData:data];
cell.myimnage.image = img;
[pool release];
}
I will call the above method in my code...
if(searching) {
//cell.textLabel.text = [copyListOfItems objectAtIndex:indexPath.row];
int blogEntryIndex = [indexPath indexAtPosition: [indexPath length] -1];
// Tell your code to load the image for a cell in the background
NSString *imgstring =[[blogEntries objectAtIndex: blogEntryIndex] objectForKey: #"image"];
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:cell, #"cell", imgstring, #"imgstring", nil];
[self performSelectorInBackground:#selector(loadImage:) withObject:dict];
//background code end here..
Thanks to deanWombourne who has given me this code....

And take a look to this document also from Apple.
http://developer.apple.com/iphone/library/documentation/cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.html
Most the time I use NSURLConnection to download things.

You can use this way:
((UIImageView *)cell.backgroundView).image = bgImage;
((UIImageView *)cell.selectedBackgroundView).image = bgImage;

Related

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

Load image to a tableView from URL iphone sdk

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"]];

image cache iphone

this is a part of my code. I'm using a asyncImageView .Everything work good. But now i want to save in the iphone all images in a path. I know i have to use NSFileManager but where?
EDIT: now i try with my code but nothing save when i compile on my iphone
// Configure the cell.
NSDictionary *dico = [self.pseudoOnline objectAtIndex:indexPath.row];
cell.pseudo.text = [dico objectForKey:#"pseudo"];
cell.sexe.text = [dico objectForKey:#"sexe"];
cell.age.text = [dico objectForKey:#"age"];
UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:[dico objectForKey:#"photo"]]]];
NSString *deskTopDir = #"/Users/***/Desktop/imagesOnline";
NSString *nomPhoto = [[cell.pseudo text]stringByReplacingOccurrencesOfString:#"\n" withString:#""];;
NSLog(#"pseudo%#",nomPhoto);
NSString *jpegFilePath = [NSString stringWithFormat:#"%#/%#.jpeg",deskTopDir,nomPhoto];
NSData *data2 = [NSData dataWithData:UIImageJPEGRepresentation(image, 0.5f)]; quality
[data2 writeToFile:jpegFilePath atomically:YES];
NSLog(#"image %#",jpegFilePath);
[image release];
CGRect frame;
frame.size.width=45; frame.size.height=43;
frame.origin.x=-5; frame.origin.y=0;
asyncImageView *asyncImage = [[[asyncImageView alloc] initWithFrame:frame] autorelease];
asyncImage.tag =999;
[asyncImage loadImageFromURL:[NSURL URLWithString:[dico objectForKey:#"photo"]]];
[cell.contentView addSubview:asyncImage];
return cell;
so now it works i can download all the pictures. But now i want to load them
I'm not sure what asyncImageView is, but it appears to get an image.
If it gets the image the way your code implies, you can put your NSFileManger method call right after:
[cell.contentView addSubview:asyncImage];
If, on the other hand, the asyncImageView fetches the image asynchronously (as it's name implies), then you should put your NSFileManager method call in asyncImageView's callback delegate.
Basically, as soon as you actually have the image, you can save the image.

OpenFlow with XML Object

Trying to use OpenFlow API for iPhone SDK.
I need the openflow to load pictures from a (image) link.
This is how it always works with local images:
loadImagesOperationQueue = [[NSOperationQueue alloc] init];
NSString *imageName;
for (int i=0; i < 10; i++) {
imageName = [[NSString alloc] initWithFormat:#"cover_%d.jpg", i];
[(AFOpenFlowView *)self.view setImage:[UIImage imageNamed:imageName] forIndex:i];
[imageName release];
NSLog(#"%d is the index",i);
}
[(AFOpenFlowView *)self.view setNumberOfImages:10];
And I tried this:
- (void)openFlowView:(AFOpenFlowView *)openFlowView requestImageForIndex:(int)index {
NSString *photoUrl = [[oldEntries objectAtIndex: 0] objectForKey: #"still"];
NSURL *photomake = [NSURL URLWithString:photoUrl];
NSLog(#"theConnection: %#",photoUrl);
NSLog(#"theConnection: %#",photomake);
AFGetImageOperation *getImageOperation = [AFGetImageOperation alloc];
// We're getting our images from the Flickr API.
getImageOperation.imageURL = photomake;
[loadImagesOperationQueue addOperation:getImageOperation];
[(AFOpenFlowView *)self.view setNumberOfImages:1];
[getImageOperation release];
}
But it just won't work. Can anyone help me?
Without knowing what 'won't work' it's hard to say, please clarify and supply the actual URL you are creating.
The only line that looks suspect is this one:
AFGetImageOperation *getImageOperation = [AFGetImageOperation alloc];
Should be:
AFGetImageOperation *getImageOperation = [[AFGetImageOperation alloc] init];
It's much easier to use:
NSURL *imageUrl = [[NSURL alloc] initWithString:[#"path/to/the/file.jpg"];
NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
UIImage *image = [UIImage imageWithData:imageData];
put all the images in an Array
and then you call you first function
for (int i=0; i < 10; i++) {
imageName = [[NSString alloc] initWithFormat:#"cover_%d.jpg", i];
[(AFOpenFlowView *)self.view setImage:**image** forIndex:i];
[imageName release];
NSLog(#"%d is the index",i);
}
[(AFOpenFlowView *)self.view setNumberOfImages:10];

Find out when all processes in (void) is done?

I need to know how you can find out when all processes (loaded) from a - (void) are done, if it's possible.
Why? I'm loading in data for a UITableView, and I need to know when a Loading... view can be replaced with the UITableView, and when I can start creating the cells.
This is my code:
- (void) reloadData {
NSAutoreleasePool *releasePool = [[NSAutoreleasePool alloc] init];
NSLog(#"Reloading data.");
NSURL *urlPosts = [NSURL URLWithString:[NSString stringWithFormat:#"%#", URL]];
NSError *lookupError = nil;
NSString *data = [[NSString alloc] initWithContentsOfURL:urlPosts encoding:NSUTF8StringEncoding error:&lookupError];
postsData = [data componentsSeparatedByString:#"~"];
[data release], data = nil;
urlPosts = nil;
self.numberOfPosts = [[postsData objectAtIndex:0] intValue];
self.postsArrayID = [[postsData objectAtIndex:1] componentsSeparatedByString:#"#"];
self.postsArrayDate = [[postsData objectAtIndex:2] componentsSeparatedByString:#"#"];
self.postsArrayTitle = [[postsData objectAtIndex:3] componentsSeparatedByString:#"#"];
self.postsArrayComments = [[postsData objectAtIndex:4] componentsSeparatedByString:#"#"];
self.postsArrayImgSrc = [[postsData objectAtIndex:5] componentsSeparatedByString:#"#"];
NSMutableArray *writeToPlist = [NSMutableArray array];
NSMutableArray *writeToNoImagePlist = [NSMutableArray array];
NSMutableArray *imagesStored = [NSMutableArray arrayWithContentsOfFile:[rootPath stringByAppendingPathComponent:#"imagesStored.plist"]];
int loop = 0;
for (NSString *postID in postsArrayID) {
if ([imagesStored containsObject:[NSString stringWithFormat:#"%#.png", postID]]){
NSLog(#"Allready stored, jump to next. ID: %#", postID);
continue;
}
NSLog(#"%#.png", postID);
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[postsArrayImgSrc objectAtIndex:loop]]];
// If image contains anything, set cellImage to image. If image is empty, try one more time or use noImage.png, set in IB
if (imageData == nil){
NSLog(#"imageData is empty before trying .jpeg");
// If image == nil, try to replace .jpg with .jpeg, and if that worked, set cellImage to that image. If that is also nil, use noImage.png, set in IB.
imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[postsArrayImgSrc objectAtIndex:loop] stringByReplacingOccurrencesOfString:#".jpg" withString:#".jpeg"]]];
}
if (imageData != nil){
NSLog(#"imageData is NOT empty when creating file");
[fileManager createFileAtPath:[rootPath stringByAppendingPathComponent:[NSString stringWithFormat:#"images/%#.png", postID]] contents:imageData attributes:nil];
[writeToPlist addObject:[NSString stringWithFormat:#"%#.png", postID]];
} else {
[writeToNoImagePlist addObject:[NSString stringWithFormat:#"%#", postID]];
}
imageData = nil;
loop++;
NSLog(#"imagePlist: %#\nnoImagePlist: %#", writeToPlist, writeToNoImagePlist);
}
NSMutableArray *writeToAllPlist = [NSMutableArray arrayWithArray:writeToPlist];
[writeToPlist addObjectsFromArray:[NSArray arrayWithContentsOfFile:nowPlist]];
[writeToAllPlist addObjectsFromArray:[NSArray arrayWithContentsOfFile:[rootPath stringByAppendingPathComponent:#"imagesStored.plist"]]];
[writeToNoImagePlist addObjectsFromArray:[NSArray arrayWithContentsOfFile:[rootPath stringByAppendingPathComponent:#"noImage.plist"]]];
[writeToPlist writeToFile:nowPlist atomically:YES];
[writeToAllPlist writeToFile:[rootPath stringByAppendingPathComponent:#"imagesStored.plist"] atomically:YES];
[writeToNoImagePlist writeToFile:[rootPath stringByAppendingPathComponent:#"noImage.plist"] atomically:YES];
[releasePool release];
}
It is as simple as returning a bool at the bottom of the selector being run in the background, and reaload the UITableView.
Thanks to #iWasRobbed:
I have never done this, but just speculating: have you tried returning a BOOL at the very end so that the reloadData function will return TRUE when it gets to that point? I am assuming (possibly incorrectly) that the device serially handles tasks one-at-a-time, so give it a shot.