Dealing with UIGraphics ImageContext ‘Memory Leaks’

Here’s the code to change the image size of an image in iOS so that then it can be saved with smaller footprint:

let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)

        

// Actually do the resizing to the rect using the ImageContext stuff

UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)

image.draw(in: rect)

        

let newImage = UIGraphicsGetImageFromCurrentImageContext()

 

UIGraphicsEndImageContext()

 

This works great if you do a few size conversions, however if you do hundreds or thousands you’ll see that “UIGraphicsGetImageFromCurrentImageContext” will hold onto the image in memory until the code returns control to the runloop, which may not happen for a long time. This may lead to crashes when iOS decides your app is using too much memory. Here’s what was happening to my app:

Screen Shot 2018 10 06 at 11 10 25 AM

To solve this I’m using a new autorelease pool at every cycle forcing it to release the memory every time. Works great, here’s the implementation of the autorelease pool code:

private func resizeImage(image: UIImage, toHeight: CGFloat) -> UIImage {

        return autoreleasepool { () -> UIImage in

             […]

             return newImage!

        }

 

    }

And the implementation of the full function for reference:

    private func resizeImage(image: UIImage, toHeight: CGFloat) -> UIImage {

        return autoreleasepool { () -> UIImage in

            let toWidth = image.size.width * (toHeight/image.size.height)

            let targetSize = CGSize(width: toWidth, height: toHeight)

            let size = image.size

        

            let widthRatio  = targetSize.width  / size.width

            let heightRatio = targetSize.height / size.height

        

            // Orientation detection

            var newSize: CGSize

            if(widthRatio > heightRatio) {

            newSize = CGSize(width: size.width * heightRatio, height: size.height * heightRatio)

            } else {

            newSize = CGSize(width: size.width * widthRatio,  height: size.height * widthRatio)

            }

        

            // Calculated rect

            let rect = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)

        

            // Resize

            UIGraphicsBeginImageContextWithOptions(newSize, false, 1.0)

            image.draw(in: rect)

        

            let newImage = UIGraphicsGetImageFromCurrentImageContext()

            UIGraphicsEndImageContext()

        

            return newImage!

        }

        

 

    }

 

Comments / questions? I’m at @MarcMasVi 

 

Marc