【发布时间】:2015-10-31 23:46:01
【问题描述】:
通过将不可见视图渲染到上下文中来创建图像时,我发现大量内存泄漏。我已将其简化为最基本的实现,并确定了导致内存泄漏的两行代码:renderInContext 和UIImagePNGRepresentation。如果我将两者都注释掉,则不会发生泄漏,但如果其中一个未注释,则会发生泄漏,如果两者都未注释,则会发生两次泄漏。 每次调用下面的方法时,内存使用量都会显着增加(如预期的那样),然后过一会儿它会减少,但比调用前的量高约 0.8 MB。
如何解决此问题以确保没有内存泄漏?
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
}
为了测试它,在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");
});
});
});
如果有更好的方法为UILabel 的layer 的图像创建NSData,我完全赞成。我想不出其他方法来获得它,除了从CGImage 创建一个CIImage 然后从CIImage 到UIImage 然后从UIImage 到NSData。请注意,它不需要很快,但它确实需要在后台线程上创建图像,以确保 UI 保持对额外输入的响应。
【问题讨论】:
-
@matt 使用模拟器,稍后将在 iPad 上尝试发布模式并报告!这并不像看起来那么奇怪,我正在做更多花哨的事情,而不仅仅是一个标签,这是显示泄漏的精简代码。我会像往常一样渲染它,但是在后台线程上弄乱 UIKit 是一个很大的禁忌,我需要应用程序在发生这种情况时继续响应。
-
@matt
UIGraphicsBeginImageContext方法是我最初采用的方法,但它不应该在后台线程上运行,我不能在主线程上运行它 - 请参阅下面链接的问题。我现在采用的方法是答案中显示的方法:改用 Core Graphics。 stackoverflow.com/questions/12843777/… -
在后台线程的 UIGraphics 上下文中呈现标签不起作用...文本不会出现。 stackoverflow.com/questions/30512053/…
-
使用 UIKit 方法绘制字符串的另一个问题是,生成的图像的文件大小比使用 UILabel 和 Core Graphics 方法生成的图像大近 3 倍。
标签: ios swift memory-leaks core-graphics