iosmemory-leaksuiviewanimation

iOS memory leak when replacing a UIImage


I've written a little iOS app which creates a slideshow based on images stored in the Documents directory (under Files).

It works but I think it's leaking memory. The reason I say this is because when running it, I see the memory creeping up in XCode each time an image is replaced.

It's not very complicated. I have:

    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.imageView.contentMode = .scaleAspectFill
        self.imageView.frame = CGRect(
            x: 0,
            y: 0,
            width: self.bounds.size.width,
            height: self.bounds.size.height
        )
        
        view.addSubview(self.imageView)
        
        /* Loads the filenames of the images */
        loadImages()
        
        displayNext()
         
        Timer.scheduledTimer(
            timeInterval: self.cycleSeconds,
            target: self,
            selector: #selector(displayNext),
            userInfo: nil,
            repeats: true
        )
    }

    @objc
    func displayNext() {
        let imageURL = self.documentsURL.appendingPathComponent(self.imageNames[self.imageIndices[self.i]])
        
        replaceImage(with: imageURL)
        
        if self.i + 1 == self.imageNames.count {
            shuffleImageIndices()
            self.i = 0
        } else {
            self.i = self.i + 1
        }
    }

The code displayNext() eventually calls this code below to transition to the next image:

    func replaceImage(with imageURL: URL) {
        assert(imageURL.isFileURL)
        
        let nextImage = UIImage(named: imageURL.path)

        UIView.transition(
            with: self.imageView,
            duration: 0.1,
            options: .transitionCrossDissolve,
            animations: { self.imageView.image = nextImage },
            completion: nil
        )
    }

Somehow all this leaks memory and I can't seem to figure out how to get rid of it.


Solution

  • The Image(named:) caches images. So you are most likely seeing a memory increase as a result of memory consumption of the cache. Check the documentation.

    You should use the constructor as UIImage(contentsOfFile:).

    Discussion:

    There is nothing wrong with using cached version. The images will be cached which improves performance but may consume more memory. This is not a memory leak but an expected behaviour. The cache itself will not crash your app due to memory consumption, it will purge the cache when a lot of memory is being used by it and memory consumption will drop.