How to clear memory after UIImageView.animationImages? - ios

I've created a new Xcode project that has only the following:
code creating an array of UIImages from png's dragged in to the project (I have tried both UIImage(named:) and UIImage(contentsOfFile:) when appending images to the array)
a UIImageView
a button which sets the imageView.animationImages = arrayOfImages and calls imageView.startAnimating()
When the button is pressed and the animation plays, the memory usage increases by 150-200MB, depending on the number of images in the image array. Then the memory usage remains at that level.
Setting imageView.animationImages = nil doesn't clear the memory. How could I go about clearing that memory?
Any suggestions would be helpful. Thanks!

1. Don't implicitely cache images
I guess you are using UIImage(named:)?
This method caches the images, see:
https://developer.apple.com/documentation/uikit/uiimage/1624146-init
Apple recommends:
If you have an image file that will only be displayed once and wish to ensure that it does not get added to the system’s cache, you should instead create your image using imageWithContentsOfFile:. This will keep your single-use image out of the system image cache, potentially improving the memory use characteristics of your app.
So using 'UIImage(contentsOfFile: String)' should solve your problem. Due to the documentation you need to supply a path to the image, the image name is not sufficient, see here:
https://developer.apple.com/documentation/uikit/uiimage/1624123-imagewithcontentsoffile
There it is also mentioned:
This method does not cache the image object.
2. Don't hold references to the images
When you are loading the images into a local array make sure to empty it.
self.imageArray = []
3. Set imageView.animationImages to an empty array
self.imageArray = []
self.imageView.animationImages = self.imageArray
Quick verification of the allocations in Instruments:
As you can see the memory is reclaimed. All good.

Related

Swift Image Memory

I am making an app where I am displaying a lot of images, for example a profile image for a player object. I have all the images stored in Media.xcassets, and the images are named after the name of the player object they belong to.
playerImage.image = UIImage(named: playerName)
I have found that after I've loaded an image, the memory usage goes up permanently, although the image is no longer displayed. It can for example go up 3/4 Mb, while the image file is just around 50kb. Even after I leave a viewController it seems the memory use from the displayed image is still there. (I am using unwind segues, so there isn't stacking of UITransitionViews)
(The increases in memory use come when I am displaying images that haven't been displayed before)
Eventually the app crashes when the memory reaches around 1GB. Is there any way to fix this, or reduce memory use?
I had the same problem just last week. What I did is to change all:
UIImage named
to:
UIImage imageWithContentsOfFile
The memory allocated with the first method seems not to be released by the Garbage collector, whereas the memory allocated with the second one yes.
Im not a swift master, but I think this will work:
UIImage(contentsOfFile: (Bundle.main .path(forResource: "imageName", ofType: "png"))!);
Hope this helps.

iOS - Optimizing. Cache images

I'm trying to optimize an iOS application which contains a lot of images and code. I have reduced the size of images with some programs but using instruments reveals that the application is still taking among 70-90mb of cache memory.
I have read that loading the resources(images) by demand and discard them when are not longer needed would be a good solution. How can i do it?
I have also a question:
When we use:
UIImage *aux = [UIImage imagenamed:#"image.png"];
and after we write aux=nil;
the image is discarded from cache?
Are only some of those images visible at a time? Write a system that loads only those images currently visible (and perhaps some that you application thinks might become visible soon). When you get a memory warning from the system, look for some images you've loaded in the past that haven't been visible for a while and release them.
To answer your second question, yes, setting a reference to nil will release it IF you are using ARC (Automatic Reference Counting), and if the reference you set to nil is the only reference to that object. All references to an object must go away before it will be released.
I would look at some of the solutions available, such as Path's FastImageCache, and see if they meet your needs. FastImageCache stores uncompressed images on disk in a format similar to Sprite Sheets (used by 2D games) so they can be loaded quickly when needed. The emphasis here is on improving scrolling performance, so if that's not an issue for you, this might not be the right tool for the job.
You might also look at this thread, although this is aimed at caching web images.
You might also take a look at The Tumblr Image Cache

save many UIImage to NSMutableArray without memory leak or similar method

I am trying to do screen capturing and saving many images into NSMutableArray. Then, I will call those images and make video. I can successfully make video. However, the problem is that I can't save many images into NSMutableArray. The application crash. I would like to know how to save those images temporarily. (not in document directory).
You will quickly run out of memory if you try to store all of those images in an array. You have two options:
Even though you say you don't want to save all of those images to the Documents folder, that might be your best approach. Save them to Documents, and then have your video creation process load the images one at a time and add them to the video.
Alternatively, you can do the renderInContext of your view that you want to capture directly to the CGContextRef that you've set up for your CVPixelBufferRef, do the appendPixelBuffer, and but then CVPixelBufferRelease immediately.
Either of these approaches will avoid holding all of the images in memory at any given time, mitigating the out of memory situation. I profiled both approaches, and each avoids the constantly growing consumption of memory that the loading of images to an array suffers.

UIImageView not releasing image data properly?

In its simplest form, my app displays 10 UIImageViews, each containing an image. Even with all UIImageViews containing images, my app uses a small enough memory footprint. However, there is a button to clear all the UIImageViews by setting all their images to nil. The problem is, when checking Memory Monitor in Instruments, the memory held by the UIImageViews is NOT going away. This doesn't appear in the Allocations instrument, confirming the remaining memory footprint is not an object, but instead graphics-based memory. If I resize the images to something smaller or larger, the memory remaining is also smaller or larger, respectively.
Why is the image data sticking around after the UIImageView's image has been set to nil?
I believe UIKit keeps a cache of images for reuse. UIImageView might be releasing the object, but a copy is kept around for performance reasons.
These images, though, should be released on receiving a memory warning. If they're not, there's two places I'd check:
Make sure the UIImageView is being dealloc'd. Use Allocations Instrument to profile your app and do whatever you need to do in the program to load those images. Then unload the images and do a search for UIImageView. As long as you're sure your program should have released all of them, if you find any in the search you know something is wrong.
I'd also check any places the image was created, for example: UIImage = [UIImage imageName:#"Foo.jpg"]; Make sure these are also being released. You can use allocations to find UIImage classes, but it'll be harder to weed out the ones that should/should not be there.
Run the static analyzer: In Xcode 4 it's under Products -> Analyze. This is a great tool for finding logic errors, over/under release (if you not using ARC) etc.
Until actual UIImageViews are themselves released, their memory will remain allocated. Additionally, if you're using convenience methods on UIImage to obtain your images, eg:
UIImage *myImage = [UIImage imageNamed:#"myImage"];
Note that your image may cached behind-the-scenes by iOS, and so even if the image is being released by you, the memory footprint may still reflect the presence of the image in memory (eventually iOS will release it, so this shouldn't adversely impact your resource consumption).

UIImage implementation / paging?

From the UIImage documentation:
In low-memory situations, image data may be purged from a UIImage
object to free up memory on the system. This purging behavior affects
only the image data stored internally by the UIImage object and not
the object itself. When you attempt to draw an image whose data has
been purged, the image object automatically reloads the data from its
original file.
What about UIImages that were not loaded from a file, but instead drawn, say, with UIGraphicsGetImageFromCurrentContext()?
I'm trying to come up with ways to optimize the memory usage of UITableViewCells with UIImageViews containing UIImages as the cells enter and are pulled from the reuse queue.
Thoughts?
Mike,
My understanding is that CGImage data is gone, so I think (this for your custom drawn image point) you are out of luck?
I actually just dealt with a similar issue with UITableViews. One thing that I did for performance was to create cells with a Nib; this was the single largest boost in performance of all the things I did, so if you are not using a Nib consider it.
You might also consider some form of preloading if you have that much data. I don't know what you are trying to implement, so this may or may be applicable.
One other note, after purging UIImage's reloading them from their files is a significant memory hit, so if you are at that point you really need to just look at memory usage overall.

Resources