2012-10-11 18 views
3

我想使用下面的代码将我的UIView转换为UIImage。renderincontext内存泄漏,如果不在主线程上使用

+ (UIImage *) imageWithView:(UIView *)view{ 
    float scale = 1.0f; 
    UIGraphicsBeginImageContextWithOptions(view.bounds.size, YES, scale); 
    [view.layer renderInContext:UIGraphicsGetCurrentContext()]; 
    UIImage* img = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    view.layer.contents = nil; 
    return img; 
} 

这个代码有两个问题。

1.当我运行在后台线程(!mainThread)

我遇到的内存泄漏问题时renderInContext被称为后台线程的代码。

2.当我运行主线程的代码

没有内存泄漏,但在iPad 3,我面临着一些性能问题(我的UI挂起时调用此方法),而从UIView的创建图像。因为我需要在一秒钟内将此函数调用5次以上,所以UI挂起会给用户带来非常糟糕的体验。

请指导我如果我在这里做错了什么?

回答

7

我认为问题1与UIKit不是线程安全的事实有关,它的使用会导致各种副作用。

如果你有像你所描述的性能问题,我看到的唯一路径是直接在辅助线程上使用CoreGraphics(而不是UIKit)。

你可以尝试这样的事情,作为一个开始:

size_t width = view.bounds.size.width; 
size_t height = view.bounds.size.height; 

unsigned char *imageBuffer = (unsigned char *)malloc(width*height*4); 
CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB(); 

CGContextRef imageContext = 
    CGBitmapContextCreate(imageBuffer, width, height, 8, width*4, colourSpace, 
       kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little); 

CGColorSpaceRelease(colourSpace); 

[view.layer renderInContext:imageContext]; 

CGImageRef outputImage = CGBitmapContextCreateImage(imageContext); 

CGImageRelease(outputImage); 
CGContextRelease(imageContext); 
free(imageBuffer); 

正如你看到的,这是相当比UIKit方式更为复杂,但它可以在一个辅助线程中运行(只要你找到一个将outputImage传回给未显示的UI线程)。

+0

你见过我的示例代码吗? 'outputImage'是一个CGImageRef,你可以通过'imageWithCGImage:'创建一个'UIImage' - 但是你应该在主线程上做最后一步... – sergio

+0

我觉得有混乱,我想将UIView到UIImage。 –

+0

ouch ...你是对的...请看我编辑的代码。这应该做到这一点。 – sergio

1

我刚刚在主线程线程上发生了这种情况(内存泄漏,原因为renderInContext)。我循环了数百个离屏视图,将它们渲染为UIImage对象,并将它们保存为PNG文件。

破碎:

for (...) { 
    ...render layer in context... 
    ...save image to disk... 
} 

作品:

for (...) { 
    @autoreleasepool { 
     ...render layer in context... 
     ...save image to disk... 
    } 
} 

有道理,适合我的是我的包裹循环的胆量在@autoreleasepool块什么问题是否解决?