UIImage causing memory leaks - objective-c

Instruments is telling me that alot of memory is being allocated when I rapidly set the image name of a UIImageview in my app. I have a UIImageView that changes its image name every frame in my game. When profiled with zombie checking in instruments, the app seems to be constantly gaining live bytes at an enourmous rate. Is there a way that I can deallocate the UIImageView's current image to stop it from doing this? I am using ARC.
My code to assign the UIImageView's image is as follows:
aPlanet.image = [UIImage imageNamed:tempPlanetName];
Where aPlanet is the UIImageView and tempPlanetName is the name of the image. This is called every frame.

[UIImage ImageNamed:] method loads the image into image view and adds this newly created uiimage object to autorelease pool. To get rid of this problem you should use -
NSString *imgPath = [NSBundle mainbundle] pathForResource:#"imageName" ofType:#"png"];
aPlanet.image = [[UIImage alloc] ]initWithContentsOfFile:imgPath];
if you are using arc then you don't need to bother about releasing this newly allocated object of uiimage which was created using initWithContentsOfFile: method.

When you use UIImage imageNamed: it will load and cache that image file. This is intended for reuse of icons and other image resources that will be utilized more than once in your application.
Apart from it seeming somewhat unusual to update an image view with a new image every frame, you should look into alternative means of loading images that you will not need more than once - or even if you do, when you need more control over its lifecycle.
For example have a look at UIImage imageWithContentsOfFile: (documented here: Apple Developer Library Reference). It explicitly states that this method will not do any caching of the image contents.
I hope this helps you, but for every frame I doubt that your performance will be good enough with this approach, but this is probably the topic of a different question should the need arise.

Related

Best image cache for loading numerous images in UITableView for IOS?

Could any one please tell me the best image cache available for loading numerous images in UITableviewcell?
Currently i am using SDWebimageCache but it seems it is creating problems in IOS9 particularly in iPad where the table scrolling makes the app to crash.
Help me with SDWebimagecache alternative.
The class which i used from SDWebImageCache is:
[cell.imgMain sd_setImageWithURL:imageLoadUrl
placeholderImage:[UIImage imageNamed:#"*placeholder image*"]
options:SDWebImageRefreshCached];
The class which i used from UIIMageView + AFNetworking is:
[cell.imgMain setImageWithURLRequest:[NSURLRequest requestWithURL:imageUrl]
placeholderImage:[UIImage imageNamed:#"wachizLogoIcon.png"]
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
cell.imgMain.image=image;
}
failure:nil];
But still the application crashes and shows the following screen:
APPLICATION CRASHES IN IOS 9 and sometimes for IOS 8.4
Please help me from this situation. Lots of pressure ...
AFNetworking has a great UIImage category that does this well and works on iOS9. I too had issues with SDWebimageCache on iOS9.
Take a look at AsyncImageView.
AsyncImageView includes both a simple category on UIImageView for loading and displaying images asynchronously on iOS so that they do not lock up the UI, and a UIImageView subclass for more advanced features. AsyncImageView works with URLs so it can be used with either local or remote files.
Loaded/downloaded images are cached in memory and are automatically cleaned up in the event of a memory warning. The AsyncImageView operates independently of the UIImage cache, but by default any images located in the root of the application bundle will be stored in the UIImage cache instead, avoiding any duplication of cached images.
The library can also be used to load and cache images independently of a UIImageView as it provides direct access to the underlying loading and caching classes
You can use JMImageCache For lazy loading of image in UITableView

set UIImage:nil in scrollview doesn't release memory with ARC if already referenced outside of scrollview

Here's what my app does.
It requests about 100 images from the server when it starts up. It stores
those images in model objects, we'll call them modelObject.storedImage
The modelObject also has a viewObject, which is a UIImageView subclass
The app has a 2D scrollview that sets all 100 viewObjects as subviews, with up to 16 of those shown in the scrollview content area at any give time
When you scroll to a given area, it finds the 16 images from the appropriate
modelObject.storedImage and does
modelObject.viewObject.image = modelObjects.storedImage;
When a viewObject scrolls out of the content area, it is purged from the view
[modelObject.viewObject setImage:nil];
[modelObject.viewObject removeFromSuperview];
The problem is, despite the purging, memory keeps growing as you scroll to new areas of the scrollview content area. Memory from putting the former modelObject.viewObject.images on the scrollview is not released. So if you scroll to enough new areas, memory use gets out of control.
To be clear, when the app first loads the 100 images into the modelObject.storedImages, memory does not get out of control. Furthermore, if I comment this out
//modelObject.viewObject.image = modelObjects.storedImage;
then memory also stays fine (but of course the scrollviews subviews don't show any image).
I did see this question "Setting uiimage to nil doesn't release memory with ARC" but I believe it's different because in my app I can't afford to keep requesting images over and over from the server. They must sit at modelObject.storedImage once they've been requested, always ready to be displayed when their corresponding viewObject is scrolled to.
Surely there must be a way to tell ARC to release the memory for these nil images? Thanks in advance for your help!
If images are created by imageNamed:, then no way to manually to release memory, you can optimize it by imageWithContentsOfFile, thanks to you are using images for server, I think you used imageWithContentsOfFile. :)
You can try use #autoreleasepool {} at scrolling method to release memory in real time.
You can try release viewObject instead of removeFromSuperview, maybe what you should store is viewFrame rather than viewObject.
Hope offer you some help.
So I went around this problem and did this as a solution. I'd be curious to see if someone has a more robust idea. I made a copy of the image and set the copy on the scrollview. Now when I purge that copy, its memory is actually released (thank you!!), while the original image still sits comfortably in the model. Note, it did not work to simply copy the image's CGImage and make a copy off that, in which case memory did not release. I had to make a new copy using a UIGraphicsImageContext.
Code to set the image on Scrollview:
UIImage *imageToCopy = modelObject.imageStore;
CGSize size = imageToCopy.size;
UIGraphicsBeginImageContext(size);
[imageToCopy drawInRect:CGRectMake(0, 0, imageToCopy.size.width, imageToCopy.size.height)];
UIImage *copiedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[modelObject.viewObject setImage:copiedImage];
Code to purge when it's off the scrollview's content area:
[modelObject.viewObject setImage:nil];
[modelObject.viewObject removeFromSuperview];
The only problem was that drawing those image contexts used a lot of memory, so I added this modification to make the drawing smaller:
...
CGSize size = imageToCopy.size;
size.width *= .2;
size.height *= .2;
UIGraphicsBeginImageContext(size);
[imageToCopy drawInRect:CGRectMake(0, 0, imageToCopy.size.width*.2, imageToCopy.size.height*.2)];
...

Why does nil-checking a table view cell property cause one of my cells to copy another?

My table view loads pictures through SDWebImage (async image downloading/cache category for UIImageView) in each tableView:cellForIndexPath:.
// 'spot' is a dictionary of this cell's attributes
NSURL* imageURL = [NSURL URLWithString:(NSString*)[spot objectForKey:#"Image"]];
UIImage* placeholderImage = [UIImage imageNamed:#"placeholder.png"];
^ Loads the images, but is constantly having to make requests or pull from the cache. So I wanted to see if the rendered cells were stored in memory, so I could only make requests for images when I need them. I went about this by adding a simple check for the image property of the image view.
if (!cell.pictureView.image)
{
NSURL* imageURL = [NSURL URLWithString:(NSString*)[spot objectForKey:#"Image"]];
UIImage* placeholderImage = [UIImage imageNamed:#"placeholder.png"];
[cell.pictureView setImageWithURL:imageURL placeholderImage:placeholderImage options:SDWebImageCacheMemoryOnly];
}
This works and keeps my images from having to reload after exiting and reentering the application. But in one of my cells that has a purposely bad image url (for debugging), the image- which used to remain as the imageNamed:#"placeholder"- is now the same image as my second cell.
I'm curious what kind of cell-reuse/cache magic is causing the cell to take the picture of a previous cell.
What is the best way to retain cell properties and only set them when needed?
It's very likely the issue is with the image package you are using. If you are making repeated URL requests to grab images, it is probably best practice to implement NSURLCache, which is a fairly simple and handles caching perfectly so it is not an issue. This is the NSHipster guide on how to use it. Other solutions tend towards these sorts of issues. Since it is a category on UIImageView, it could be any number of things causing issues with UIImageView's implementation when getting used in the cell.

page-based with storyboard dont dealloc

I am developing a complete application using the template "page-based storyboard".
But whenever I turn page, I see thru the instruments that the amount of memory allocated only increase and never decrease, so until a crash occurs.
Trying in iPad device crash too.
To simplify and try to find the problem, I created a test app using the same template and opting for ARC, only loading the image of the pages that I use and no change anything in the original apple code, even in this simple application the problem occurs.
I think the problem is because all page are stay allocated like this issue
PageViewController: How to release ViewControllers added to it?
but I m using storyboard, so, where is:
PageView *pView = [[PageView alloc] init];
I have:
MWViewController *dataViewController = [storyboard instantiateViewControllerWithIdentifier:#"MWDataViewController"]
I try to put autorelease but no effect.
The problem that I was having is that I was using background image in all pages and the imageNamed: method caches images which makes my memory footprint grow. I used the UIImage initWithContentsOfFile: method and my foot print stayed mostly flat.

objective-c memory friendly way for background image

i have an ipad app (>30 views / pages) each view has a unique background.
the problem:
whats the best way to set the background (memory friendly)
is there a better way than adding: uiimageview "backgroundView" as a subview?
version1:
[[UIImage alloc] initWithData:imageData];
which seems to be problematic with the retina switch
version2:
self.layer.contents = (id)image.CGImage;
version 3:
UIImage* image = [UIImage imageWithContentsOfFile:fileLocation];
version 2 seems to work fine. maybe someone tell me whats the best approach, and why ;)
thank you
Alex
CGImage is problematic with retina ... version3. is best for memory friendly !
In version 2, you generate a new image object which you have to release manually if you don't use ARC. Version 3 uses an autoreleased object.
Both versions are equal in memory-friendlyness.
I'd prefer version 3 because you don't have to do anything yourself to free the memory.
You could also use [UIImage imageNamed:#"image-name.png"], which also generates an autoreleased object.
If you want it as memory-friendly as possible, you should consider using PVR images, as those are natively supported by the graphics hardware.
Best,
Flo