After reading a number of answers on SO and other articles (see below) what is the best method to manage memory when you are loading multiple images into an animation array?
http://www.alexcurylo.com/2009/01/13/imagenamed-is-evil/
Here are my goals:
As Apple states https://forums.developer.apple.com/thread/17888
Using the UIImage(named: imageName)
caches the images, but in my case after playing 2-3 animations in a row iOS terminates the App (the OS does not respond to a low memory warning and instead terminates the App - see end of code below)
I don't want to cache the images and rather we could either:
Here is my code:
// create the Animation Array for each animation
func createImageArray(total: Int, imagePrefix: String) -> [UIImage]{
var imageArray: [UIImage] = []
for imageCount in 0..<total {
let imageName = "\(imagePrefix)-\(imageCount).png"
let image = UIImage(named: imageName)! // here is where we need to address memory and not cache the images
//let image = UIImage(contentsOfFile: imageName)! // maybe this?
imageArray.append(image)
}
return imageArray
}
// here we set the animate function values
func animate(imageView: UIImageView, images: [UIImage]){
imageView.animationImages = images
imageView.animationDuration = 1.5
imageView.animationRepeatCount = 1
imageView.startAnimating()
}
// Here we call the animate function
animation1 = createImageArray(total: 28, imagePrefix: "ImageSet1")
animation2 = createImageArray(total: 53, imagePrefix: "ImageSet2")
animation3 = createImageArray(total: 25, imagePrefix: "ImageSet3")
func showAnimation() {
UIView.animate(withDuration: 1, animations: {
animate(imageView: self.animationView, images: self.animation1)
}, completion: { (true) in
//self.animationView.image = nil // Maybe we try the following?
//self.animationView.removeFromSuperview()
//self.animationView = nil
})
}
Based on SO responses, it looks like this may be the best method to prevent the images from being cached, but it doesn't seem to work in my code:
let image = UIImage(contentsOfFile: imageName)!
I have also tried this but it doesn't seem to work either:
func applicationDidReceiveMemoryWarning(application: UIApplication) {
NSURLCache.sharedURLCache().removeAllCachedResponses()
}
I also tried the following article (removeFromSuperview) in the completion block but I couldn't get this to work either (see my code above):
https://www.hackingwithswift.com/example-code/uikit/how-to-animate-views-using-animatewithduration
New Code:
// create the Animation Array for each animation
func createImageArray(total: Int, imagePrefix: String) -> [UIImage]{
var imageArray: [UIImage] = []
for imageCount in 0..<total {
let imageName = "\(imagePrefix)-\(imageCount).png"
//let image = UIImage(named: imageName)! // replaced with your code below
if let imagePath = Bundle.mainBundle.path(forResource: "ImageSet1" ofType: "png"),
let image = UIImage(contentsOfFile: imagePath) {
//Your image has been loaded }
imageArray.append(image)
}
return imageArray }
It's pretty simple. UIImage(named:)
caches images, and UIImage(contentsOfFile:)
does not.
If you don't want your images to be cached, use UIImage(contentsOfFile:)
instead. If you can't get that to work then post your code and we'll help you debug it.
Be aware that UIImage(contentsOfFile:)
does not look for files in your app bundle. It expects a full path to the image file. You will need to use Bundle
methods to find the path to the file and then pass that path to UIImage(contentsOfFile:)
:
if let imagePath = Bundle.mainBundle.path(forResource: "ImageSet1" ofType: "png"),
let image = UIImage(contentsOfFile: imagePath) {
//Your image has been loaded
}
Your code is loading all the images for all 3 animations into an array of images and never releasing them, so the fact that the system caches those images seems pretty irrelevant. In a low memory condition the system should flush the cached copies of the images, but your code will still hold all those images in your arrays so the memory won't get freed. It looks to me like it's your code that's causing the memory problem, not the system's images caching.
Your code might look like this:
func createImageArray(total: Int, imagePrefix: String) -> [UIImage]{
var imageArray: [UIImage] = []
for imageCount in 0..<total {
let imageName = "\(imagePrefix)-\(imageCount)"
if let imagePath = Bundle.main.path(forResource: imageName,
ofType: "png"),
let image = UIImage(contentsOfFile: imagePath) {
imageArray.append(image)
}
}
return imageArray
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With