-1

I'm seeing a large memory leak when creating images by rendering a non-visible view into a context. I've reduced it down to the most basic implementation and have determined two lines of code that are contributing to the memory leak: renderInContext and UIImagePNGRepresentation. If I comment both out, no leak occurs, but if one of them is uncommented a leak occurs, if both are uncommented two leaks occur. Each time the method below in invoked, memory usage increases significantly (as expected), then after a moment it decreases but is ~0.8 MB higher than the amount it was before the invocation.

How can I resolve this to ensure there are no memory leaks?

public class func imageDataForSymbol(symbol: String) -> NSData? {
    var imageData: NSData!

    let dimension = 180

    let label = UILabel(frame: CGRectMake(0, 0, CGFloat(dimension), CGFloat(dimension)))
    label.text = symbol

    let colorSpace = CGColorSpaceCreateDeviceRGB()
    let bitmapInfo = CGImageAlphaInfo.PremultipliedLast.rawValue
    let bitmapContext = CGBitmapContextCreate(nil, dimension, dimension, 8, 0, colorSpace, bitmapInfo)!

    label.layer.renderInContext(bitmapContext) //FIXME: causing leak!!

    let cgImage = CGBitmapContextCreateImage(bitmapContext)!
    let image = UIImage(CGImage: cgImage)
    imageData = UIImagePNGRepresentation(image)! //FIXME: causing leak!!

    return imageData
}

To test it, in viewDidAppear:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0), ^{
        NSData *d = [ImageGenerator imageDataForSymbol:@"W"];

        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"triggered");
        });
    });
});

If there is a better way to create NSData for an image of a UILabel's layer, I'm all for it. I could not think of a different way to obtain it though, other than creating a CIImage from CGImage then from CIImage to UIImage then from UIImage to NSData. Note that it doesn't need to be fast, but it does need to create the image on a background thread to ensure the UI remains responsive to additional input.

Jordan H
  • 52,571
  • 37
  • 201
  • 351
  • @matt Using Simulator, will try release mode on an iPad in a bit and report back! It's not as odd as it seems, I am doing more fancy things other than just a single label, this is the trimmed down code that exhibits the leaks though. I would just render it as I normally would, but messing with UIKit on a background thread is a big no-no, and I need the app to continue to be responsive while this occurs. – Jordan H Oct 31 '15 at 23:59
  • @matt The `UIGraphicsBeginImageContext` approach was the approach I took originally, but that should not be run on a background thread and I cannot run it on the main thread - see the question linked below. The approach I'm now taking is the approach shown in the answer: using Core Graphics instead. http://stackoverflow.com/questions/12843777/renderincontext-memory-leak-if-not-use-on-main-thread/ – Jordan H Nov 01 '15 at 17:32
  • Rendering a label in a UIGraphics context on a background thread does not work... the text does not appear. http://stackoverflow.com/questions/30512053/swift-uilabel-text-not-renderer-when-using-renderincontext-asynchronously – Jordan H Nov 01 '15 at 19:50
  • Another problem with drawing a string using the UIKit approach, the resulting image is nearly 3x larger in file size than the images generated using a UILabel with the Core Graphics approach. – Jordan H Nov 01 '15 at 21:19

1 Answers1

-1

pair CGColorSpaceCreateDeviceRGB with CGColorSpaceRelease

pair CGBitmapContextCreate with CGContextRelease

pair CGBitmapContextCreateImage with CGContextRelease

Toni lee
  • 485
  • 3
  • 12
  • 1
    Technically, Swift does not manage memory, it's ARC that does the heavy lifting... – Henri Normak Nov 01 '15 at 20:01
  • Really? But in Obj-C with ARC, I alway use the *Release functions, and they work fine. As I can remember, ARC does not manager memory for Core Foundation. – Toni lee Nov 02 '15 at 16:08