3

我正在尝试使用以下代码将我的 UIView 转换为 UIImage 。

+ (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 上,我在从 UIView 创建图像时遇到了一些性能问题(调用此方法时我的 UI 挂起)。由于我需要在一秒钟内调用此函数超过 5 次,因此 UI 挂起会给用户带来非常糟糕的体验。

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

4

2 回答 2

8

我认为问题 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 线程)。

于 2012-10-11T16:22:15.740 回答
2

我刚刚在线程上发生了这种情况(由于内存泄漏renderInContext) 。我循环了数百个屏幕外视图,将它们渲染为对象,并将它们保存为 PNG 文件。为我解决问题的方法是将循环的内容包裹在一个块中:UIImage@autoreleasepool

破碎的:

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

作品:

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

有道理,对吧?

于 2013-08-30T05:27:52.700 回答