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.
Related
NSURL *url = [NSURL URLWithString:#"yourimage"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[[UIImage alloc] initWithData:data] autorelease];
This code i used to get the image but how to show it in table cell.
try this,
- (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];
}
NSURL *url = [NSURL URLWithString:[imageArray objectAtIndex: [indexPath row]]];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[[UIImage alloc] initWithData:data] autorelease];
[[cell imageView] setImage:img];
return cell;
}
FirstLy You need To parse That JSON file In Your iOS Application.
I guess You get Some URL from That JSON for The Image So You need To Download Image Form That Prased URL and Can set That IMage Over ANy UIIMageView and you can set That UIIMageView to The Content View Of UITablViewCell.
Here You Need To Just Manage One THing Suppose You have Many Images To be Downlaod Form The Particular path.So You should Take Care of The UI Interaction also
Here Is Good Example Of How TO download Images form The URL and set That DownLoaded Image Over The UIImageView and set That UIImageView on to the ContentView of UITableViewcell.In this Example you'll also see The Way of How Can you Add The These Images Over The TableViewcEll.
Here Is The Link For That Example
I hope It may help You.
You can do it with
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Cell"];
[[cell imageView] setImage:img];
But thats probably not going to run very well because you're downloading the images synchronously and that will most likely make your app stutter.
You should use lazy loading for the images, for an example take a look at
http://developer.apple.com/library/ios/#samplecode/LazyTableImages/Introduction/Intro.html
This works for me:
NSURL *url = [NSURL URLWithString:[aTweet objectForKey:#"profile_image_url"]];
NSData *imgData = [NSData dataWithContentsOfURL:url];
cell.imageView.image = [UIImage imageWithData:imgData];
I'm writing an app that needs store a few images in cache. I'm trying to do it with NSCache and the code seems to be well but don't save the images in cache. I have this code:
cache is global, declared in .h: NSCache *cache;
-(UIImage *)buscarEnCache:(UsersController *)auxiliarStruct{
UIImage *image;
[[cache alloc] init];
NSLog(#"cache: %i", [cache countLimit]);
if ([cache countLimit] > 0) { //if [cache countLimit]>0, it means that cache isn't empty and this is executed
if ([cache objectForKey:auxiliarStruct.thumb]){
image = [cache objectForKey:auxiliarStruct.thumb];
}else{ //IF isnt't cached, is saved
NSString *imageURLString = [NSString stringWithFormat:#"http://mydomain.com/%#",auxiliarStruct.thumb];
NSURL *imageURL = [NSURL URLWithString:imageURLString];
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
image = [UIImage imageWithData:imageData];
[cache setObject:image forKey:auxiliarStruct.thumb];
}
}else{ //This if is executed when cache is empty. IS ALWAYS EXECUTED BECAUSE FIRST IF DOESN'T WORKS CORRECTLY
NSString *imageURLString = [NSString stringWithFormat:#"http://mydomain.com/%#",auxiliarStruct.thumb];
NSURL *imageURL = [NSURL URLWithString:imageURLString];
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
image = [UIImage imageWithData:imageData];
[cache setObject:image forKey:auxiliarStruct.thumb];
}
return image;
}
This function is called in other function with this:
UIImage *image = [self buscarEnCache:auxiliarStruct];
This works because the image is displayed on screen but isn't saved in cache, the line that I think fails is:
[cache setObject:image forKey:auxiliarStruct.thumb]; //auxiliarStruct.thumb is the name of the image
Someone knows why cache doesn't work?? Thanks!!
ps: sorry for my english, I know is bad
Every time the method buscarEnCache: is called an new cache object is created with the line:
[[cache alloc] init];
Thus the old cache just leaked and is not available any more.
place the cache = [[NSCache alloc] init]; in the init method of the class.
There is no need to check for the countLimit.
-(UIImage *)buscarEnCache:(UsersController *)auxiliarStruct{
UIImage *image = [cache objectForKey:auxiliarStruct.thumb];
if (!image) {
NSString *imageURLString = [NSString stringWithFormat:#"http://mydomain.com/%#",auxiliarStruct.thumb];
NSURL *imageURL = [NSURL URLWithString:imageURLString];
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
image = [UIImage imageWithData:imageData];
[cache setObject:image forKey:auxiliarStruct.thumb];
}
return image;
}
You might want to place the fetch of the image in a method that runs in an other thread and return some kind of placeholder image.
As well as the answer provided by #rckoenes, you aren't allocating the cache instance correctly anyway; it should be:
cache = [[NSCache alloc] init];
Which should be moved into your init method.
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
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"]];
I have images cached and I want to resize them and display them in a tableview. Here's the code:
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://huntify.com%#",[[hunts objectAtIndex:indexPath.row] iconURL]]];
UIImage *logo = [[UIImage alloc] initWithContentsOfFile:[[ASIDownloadCache sharedCache] pathToCachedResponseDataForURL:url]];
logo = [logo imageScaledToSize:CGSizeMake(100.0, 100.0)];
[[cell imageView] setImage:logo];
This works fine but I wonder how I should release the UIImage. I suspect that releasing the "logo" after setting the image-property to the UIImageView is wrong because of the imageScaledToSize-method. Should I assign a new UIImage when resizing and release the old one?
You have a big memory leak here. By assigning another value to logo in logo = [logo imageScaledToSize:CGSizeMake(100.0, 100.0)];, you lose the reference to the original image you would need to release. So yes, you should use a new variable to store the result of imageScaledToSize: and then release the original logo.
Do this-
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://huntify.com%#",[[hunts objectAtIndex:indexPath.row] iconURL]]];
UIImage *logo = [[UIImage alloc] initWithContentsOfFile:[[ASIDownloadCache sharedCache] pathToCachedResponseDataForURL:url]];
UIImage *resizedLogo = [logo imageScaledToSize:CGSizeMake(100.0, 100.0)];
[[cell imageView] setImage:resizedLogo];
[logo release];
Remember, you are only releasing owenership of an object when you [logo release], you are not dealloc'ing it.