Can anyone please enlighten me how to clear cache while scrolling through images?
i m using SDwebImage package.It is working till 110 photos after that it giving memory receive warning and getting crash i have tried following method also but no success:
SDImageCache *imageCache = [SDImageCache sharedImageCache];
[imageCache clearMemory];
[imageCache clearDisk];
[imageCache cleanDisk];``
after this code it scroll 10 more photo after that get crash.
try [imageCache release]; or autorelease while initiating or try writing in
-(void)dealloc
{
[super dealloc];
[imageCache release];
}
Related
I am using AFNetworking 3.0's UIImageView+AFNetworking to display images in a UICollectionView.
However as I keep scrolling, the memory usage of my app keeps growing forever. I used Instruments Allocations tool and am able to narrow down the issue to CG Raster Data which keeps growing for every image which is loaded. Looking at the details of the CG Raster Data, The responsible caller is cgdataprovidercreatewithcopyofdata and responsible library is CoreGraphics. For each cell loaded, a 240 KB memory is wasted.
There are a lot of similar issues on stack overflow but none really help/have a solution.
I thought this might be due to cache, so I enabled following but didn't help at all:
NSURLCache * sharedCache = [[NSURLCache alloc] initWithMemoryCapacity:0 diskCapacity:10 * 1024 diskPath:nil];
[NSURLCache setSharedURLCache:sharedCache];
I tried wrapping the setImageWithURLRequest inside an autoreleasepool but didn't help.
I tried searching for cgdataprovidercreatewithcopyofdata in the entire app but I find no hits in my app or the afnetworking. However if I remove the loading of the image, then I don't see this issue.
Also if I remove the setting of the image inside the completion handler, the memory still grows. Meaning that setImageWithURLRequest itself is the culprit and not the setting of the image inside the completion handler.
I have been struggling with this for a while, any help would be appreciated!
Here's my code for the setting of image:
[cell.thumbnail cancelImageDownloadTask];
__weak UIImageView *weakImageView = cell.thumbnail;
#autoreleasepool {
[cell.thumbnail setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://myurl/image.png"]]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
UIImageView *strongImageView = weakImageView; // make local strong reference to protect against race conditions
if (!strongImageView) return;
[UIView transitionWithView:strongImageView
duration:0.3
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^{
strongImageView.image = image;
}
completion:NULL];
}
failure:NULL];
Here's screenshots from instruments:
I used #ajay gabani response to use SDWebImage instead of AFNetworking's ImageView.
In SDWebImage it at least provided a way to clear the cache plus you can control whether the image is cached in disk or only memory.
I set the maxMemoryCountLimit to 10 but it doesn't seem to do much in my testing:
SDImageCache *imageCache = [SDImageCache sharedImageCache];
imageCache.maxMemoryCountLimit=10;
I clear the cache every few seconds:
[NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:#selector(simulateMemoryWarning) userInfo:nil repeats:YES];
- (void)simulateMemoryWarning{
[[NSNotificationCenter defaultCenter] postNotificationName:UIApplicationDidReceiveMemoryWarningNotification object:nil];
SDImageCache *imageCache = [SDImageCache sharedImageCache];
NSLog(#"Simulated");
[imageCache clearMemory];
[imageCache clearDisk];
}
For some reason when I'm downloading my image using GCD, the image will randomly start flickering.
I'll reset the content settings in simulator and it'll work once, then it'll just start flickering again.
This is the code I am using. I've got the reloads in there because if I don't reload it, the image doesn't show until I tap on the cell.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void) {
NSURL *url = [NSURL URLWithString:self.entries.arrayimage];
NSData *imgData = [NSData dataWithContentsOfURL:url];
dispatch_sync(dispatch_get_main_queue(), ^(void) {
cell.imageView.image = nil;
UIImage *img = [UIImage imageWithData:imgData];
cell.imageView.image = img;
[self.tableView reloadData];
});
});
return cell;
[self.tableView reloadData];
That's because you are using dispatch_async(dispatch_get_global_queue to async load imageData from file. Using this style load image in cellForRow will make cell image should should previous image first. Then finish async load, will call dispatch_sync(dispatch_get_main_queue(), to load the image you want to. Therefore, whenever you reloadData or any other methods to call cellForRow, the cell image will flicker.
I know you want to load image without blocking main thread, but it's not a good way.
Check out apple sample code for Lazy Image loading. And also I checked your code and found that you always downloading image from URL. Instead of that its good to download and save image in caches and then load image from next time in cellForRowAtIndexPath method from local caches if available.
Is this code in cellForRowAtIndexPath:?
If that is the case, the problem here is that all the cells are infinitely reloading the table. You should not be calling reloadData in any of datasource methods that are triggered by reloadData.
What you have is basically an infinite loop of reloading. (reloadData triggers cellForRowAtIndexPath: which once again triggers reloadData).
My suggestion is to use an external component for this as aeskreis posted in his comment.
SDWebImage is probably the best one out there and will allow you to simplify all of the code you have there into simply:
NSURL *url = [NSURL URLWithString:self.entries.arrayimage];
[cell.imageView setImageWithURL:url];
Okay Guys I found out the problem. It was constantly reloading the data which caused te flickering. instead of [self.tableView reloadData] I replaced it with this method:
[cell setNeedsLayout];
I believe this method detects if anything has been changed, and then updates it (from my memory of a couple hours ago so it's probably not 100% accurate), but that fixed my problem.
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSURL *url = [NSURL URLWithString:self.entries.arrayimage];
NSData *imgData = [NSData dataWithContentsOfURL:url];
dispatch_sync(dispatch_get_main_queue(), ^{
UIImage *img = [UIImage imageWithData:imgData];
cell.imageView.image = img;
//[self.tableView reloadData];
[cell setNeedsLayout];
});
});
return cell;
I'm loading images from the server in UItableViewCell.
Since Each Image takes 10MB size It cause memory problem.
App crashes Whenever I do scroll over the tableView
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
locationcellObject=[self.tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
NSDictionary *temp= [sortedArray objectAtIndex:indexPath.row];
locationcellObject.title.text=[temp objectForKey:#"locationtitle"];
locationcellObject.subtitle_Lbl.text=[temp objectForKey:#"category"];
NSString *trimmedtitle = [[temp objectForKey:#"locationtitle"]stringByReplacingOccurrencesOfString:#" " withString:#""];
NSString *name=[NSString stringWithFormat:#"images/%#.png",trimmedtitle];
NSString *imageName=[NSString stringWithFormat:#"http://my_URL_HERE/%#",name];
_tempData = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageName]];
UIImage *display=[[UIImage alloc]initWithData:_tempData];
locationcellObject.locationPic_img_View.image=display;
locationcellObject.locationPic_img_View.contentMode=UIViewContentModeScaleAspectFit;
return locationcellObject;
}
Is there any Easy way to do it??
Download your images in background thread, download images with in the block. by this way two thread will be running in your app main thread and background thread. it will be reduces load on main thread.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Call your function or whatever work that needs to be done
//Code in this part is run on a background thread
dispatch_async(dispatch_get_main_queue(), ^(void) {
//Stop your activity indicator or anything else with the GUI
//Code here is run on the main thread
});
});
And also add downloaded images in cache using NSCache,by which next time your images will be loaded from cache,
you can check this link here you can find how to add images in cache
Please refer THIS tutorial. It describes fetching/loading images in UItableView in efficient way.
1 ) you should do the downloading in the background
2 ) make a thumbnail of the image (image with smaller size)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^ {
_tempData = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageName]];
UIImage *display=[[UIImage alloc]initWithData:_tempData];
//make a thumbnail of the image
UIImage *display;
CGSize destinationSize = ...;
UIGraphicsBeginImageContext(destinationSize);
[originalImage drawInRect:CGRectMake(0,0,destinationSize.width,destinationSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//
dispatch_async(dispatch_get_main_queue(), ^{
//put result to main thread
locationcellObject.locationPic_img_View.image= newImage;
});
});
Im trying to implement a simple video stream but for some reason my memory won't get freed:
(void)updateImage:(UIImage *)image{
self.indicator.hidden = TRUE;
//CGImageRelease([self.imageView.image CGImage]);
self.imageView.image = nil;
self.imageView.image = image;
[self.imageView setNeedsDisplay];
}
If I use
CGImageRelease([self.imageView.image CGImage]);
memory will be freed. But when I return to a previous view controller the app will crash as it tries to free the allocated memory for that image, which I already freed. This method is called from a async task which creates an image using:
UIImage *image = [UIImage imageWithCGImage:cgImage];
CGImageRelease(cgImage);
CGDataProviderRelease(provider);
CFRelease(data);
As I understood it the UIImage now owns the CGImage and I shouldn't have to release it.
So is there anyway to ensure that the UIImage is freed when I updated the UIImageView with a new image?
Ok so I finally figured out the problem.
As I said I was using some background thread to perform the image update, the solution was to add it as a autorelease pool as following:
#autoreleasepool {
[self.delegate performSelectorOnMainThread:#selector(updateImage:) withObject:[self fetchImage] waitUntilDone:NO];
}
I am using https://github.com/rs/SDWebImage to load images in a UITableView.
Here is how i implemented it (simple), inside cellForRowAtIndexPath
[cell.imageView setImageWithURL:[NSURL URLWithString:[item valueForKey:#"icon"]]placeholderImage:[UIImage imageNamed:#"icon_events_default.png"]];
After images are loaded in UITableView, i scroll down, and than again up, and i receive error:EXC_BAD_ACCESS
- (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder
{
SDWebImageManager *manager = [SDWebImageManager sharedManager];
// Remove in progress downloader from queue
[manager cancelForDelegate:self];
UIImage *cachedImage = [manager imageWithURL:url];
if (cachedImage)
{
//EXC_BAD_ACCESS hapens here
self.image = cachedImage;
}
else
{
if (placeholder)
{
self.image = placeholder;
}
[manager downloadWithURL:url delegate:self];
}
}
Any help is really appreciated.
Did you run this code through Zombies in Instruments? That should point to the problem immediately. Just select Profile from the Product menu, Instruments will start, select the Zombie instrument, then run the test scenario which causes this problem, and you should see a zombie pop up that shows how an object is still being used even though it's no longer valid.
If I had to guess, you're UITableViewCell is not being properly retained and it's either getting released or reused too quickly before the image at the url loads.