我看到一個巨大的內存泄漏時,通過渲染一個不可見的視圖到上下文創建圖像。我已經將它簡化爲最基本的實現,並確定了導致內存泄漏的兩行代碼:renderInContext
和UIImagePNGRepresentation
。如果我將兩者都評論出來,則不會發生泄漏,但如果其中一個未註釋,則會發生泄漏,如果兩者均未註釋,則會發生兩處泄漏。 每次調用下面的方法時,內存使用量會顯着增加(如預期的那樣),然後一段時間後會下降,但比調用前高出約0.8 MB。內存泄漏renderInContext和UIImagePNGRepresentation
如何解決這個問題以確保沒有內存泄漏?
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
,我完全贊成。我想不出有什麼不同的方式來獲得它,除了創建CIImage
從CGImage
然後從CIImage
到UIImage
然後從UIImage
到NSData
。請注意,它不需要很快,但它確實需要在後臺線程上創建圖像,以確保UI保持對其他輸入的響應。
@馬特使用模擬器,將嘗試在iPad發佈模式了一下,報到!這並不像看起來那麼古怪,除了單一標籤之外,我正在做更多奇特的事情,但這是修剪下來的代碼,儘管它表現出了泄漏。我只會像往常一樣渲染它,但在後臺線程上搞UIKit是一個很大的禁忌,我需要應用程序在發生這種情況時繼續響應。 – Joey
@matt'UIGraphicsBeginImageContext'方法是我最初採用的方法,但不應該在後臺線程上運行,並且我無法在主線程上運行它 - 請參閱下面鏈接的問題。我現在採用的方法是在答案中顯示的方法:使用Core Graphics代替。 http://stackoverflow.com/questions/12843777/renderincontext-memory-leak-if-not-use-on-main-thread/ – Joey
在後臺線程的UIGraphics上下文中呈現標籤不起作用...文本沒有出現。 http://stackoverflow.com/questions/30512053/swift-uilabel-text-not-renderer-when-using-renderincontext-asynchronously – Joey