3

Is there a 'nuclear option' to release the images from the image array? I would like to play the first animation1 (ImageSet1), then in the completion block delete this animation and then load and play the second animation2 (ImageSet2), and so on: wash, rinse, repeat - you get it :)

First, I define the instance variables of my ViewController:

var animation1: [UIImage] = []
var animation2: [UIImage] = []
var animation3: [UIImage] = []

Then I create an 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)!
    imageArray.append(image)
    }
    return imageArray
    }

Then I set the animate values:

func animate(imageView: UIImageView, images: [UIImage]){
    imageView.animationImages = images
    imageView.animationDuration = 1.5
    imageView.animationRepeatCount = 1
    imageView.startAnimating() }

    animation1 = createImageArray(total: 28, imagePrefix: "ImageSet1")
    animation2 = createImageArray(total: 53, imagePrefix: "ImageSet2")
    animation3 = createImageArray(total: 25, imagePrefix: "ImageSet3")

And lastly call the animate function

func showAnimation() {
    UIView.animate(withDuration: 1, animations: {
        animate(imageView: self.animationView, images: self.animation1)

        }, completion: { (true) in

        // Release the Images from the Array

        })
    }

I would like to release the images from the image array in the completion block to lower my memory footprint, but I can't seem to get this to work, I have tried all four examples below but there is no effect on the memory footprint:

func showAnimation() { 
UIView.animate(withDuration: 1, animations: { 
animate(imageView: self.animationView, images: self.animation1) 

}, completion: { (true) in 

self.animation1 = [] // is this correct?
self.animationView.image = nil // also doesn't work
self.animationView.removeFromSuperview() // also doesn't work
self.animation1 = nil // also doesn't work

}) 
}

After the completion block, I set the animation1 array equal to [] and it does remove the animation (you can't see it any more) but the memory footprint remains the exact same (I have also tried the other three options as well).

With the above, the memory footprint 'bumps' up each time I add the next animation and it eventually causes the OS to terminate the App

Even when you change ViewControllers, the array is still holding the images in memory

Thanks for any help :)

  • what about self.animation1.removeAll()? – Tushar Sharma Dec 10 '17 at 05:33
  • 1. See [here](https://stackoverflow.com/a/30829144/5175709) and maybe [here](https://stackoverflow.com/questions/43333328/how-can-i-deallocate-all-references-elements-from-an-array). 2. If the images are being referenced and retained from any other line in your code, then it needs it requires to be released from there as well. Additionally you should change `completion: { (true) in ` to `completion: { [weak self] (true) in ` so you avoid capturing `self` and creation of memory cylcles – mfaani Dec 10 '17 at 05:48
  • Hi @TusharSharma - thanks for your answer, I tried self.animation1.removeAll() and there is still no effect on memory (it remains the same) – Server Programmer Dec 10 '17 at 08:14
  • Thanks @Honey - is there a 'nuclear' option to release all references to the image array in one line? Also, if we call the animation in two different lines of code (in two separate functions), how would you address each line to release the animation (ie either in the completion block or in a simple function)? – Server Programmer Dec 10 '17 at 17:27

1 Answers1

0

UIImage(named: ) will always save the image in the memory stack unless there is a requirement for more memory and enough time to deallocate.

In order to release images from memory you should use the other constructor: UIImage(contentsOfFile: ) and save the images in folder instead of the Asset manager. Maybe data will work as well but i'm not sure.

Temporary / Large resources will consume the heap, you should use "temp saving" methods such as contentsOfFile to clear it from the memory.

unkgd
  • 671
  • 3
  • 12
  • 1
    I'd create an external folder named "Animations" move the animations there (outside of the assets - because you can't get a path for the assets), and then use: Bundle.main.path(forResource: ofType: ) to load the path's of the animation images, and use UIImage(contentsOfFile: ____) with the given path – unkgd Dec 10 '17 at 17:39
  • 1
    Are you sure the images are part of the project and you are using the correct names (without extension)? because if Bundle.main.path(forResource) returns nil it means it can't load the images, maybe try and clean the project prior to re-compiling. Which parameter is nil? the bundlePath or the image? – unkgd Dec 11 '17 at 08:08
  • Hi @unkgd - appreciate your answers. I have created a new question in light of your comments and if you would like to post here I will accept your answer: https://stackoverflow.com/questions/47744665/how-to-convert-uiimage-to-imagewithcontentsoffile-in-swift-3-0 – Server Programmer Dec 11 '17 at 23:11