“[CALayer renderInContext]”在iPhone X

时间:2018-01-25 15:30:16

标签: ios objective-c iphone calayer iphone-x

我有一个自定义UIView,我希望将其呈现为UIImage。自定义UIViewUIImageView的子类。

在这个视图中,我正在渲染一些UI元素(在图像上绘制一堆圆圈)。添加的圈数可以达到数千个。

我使用这个简单的代码段将视图呈现为UIImage

// Create the UIImage (code runs on the main thread inside an @autorelease pool)
UIGraphicsBeginImageContextWithOptions(viewToSave.image.size, viewToSave.opaque, 1.0);
[viewToSave.layer renderInContext:UIGraphicsGetCurrentContext()];
imageToSave = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

// Since I'm rendering some stuff inside the .layer of the UIView,
// I don't think I can use "drawViewHierarchyInRect: afterScreenUpdates:"

以下是从Instruments获取的内存分配,在一个示例中添加了~3000个圆作为子视图:

MEMORY ALLOCATIONS (HEAP + ANONYMOUS VM)

现在这里有一个奇怪的部分......运行正常,我可以多次渲染图像(连续)并将其保存在iPhone 5,iPhone 5s,iPhone 6s,iPad Air 2,iPad Mini等设备的图库中4 ...但是相同的代码会在 iPhone X 上触发内存警告并最终导致应用程序崩溃...

不幸的是,我无法访问iPhone X,并且报告此内容的人无法访问Mac,因此我无法进行更深入的调查。

我真的不知道我做错了什么...你知道iPhone X有什么不同之处吗?我一直在努力解决这个问题......

4 个答案:

答案 0 :(得分:1)

我猜这个问题与CALayer:renderInContext:如何在需要扩展的上下文中处理数千个视图的处理有关。是否可以尝试自己渲染子视图?然后通过使用检测来比较并验证它是否更好。

UIImage *imageToSave = [self imageFromSubLayer:viewToSave];

- (UIImage *)imageFromSubLayers:(UIImageView *)imageView {
    CGSize size = imageView.image.size;
    UIGraphicsBeginImageContextWithOptions(size, YES, .0);
    CGContextRef context = UIGraphicsGetCurrentContext();
    for (CALayer *layer in imageView.layer.sublayers)
        [layer renderInContext:context];
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return image;
}

答案 1 :(得分:0)

我最近在一个应用程序中编写了一个方法,我将UIView转换为UIImages(因此我可以在进度视图/标签栏上显示渐变)。我最终解决了以下代码,我使用此代码渲染标签栏按钮,它适用于所有设备,包括X.

目标C:

UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithSize:gradientView.bounds.size];
    UIImage *gradientImage = [renderer imageWithActions:^(UIGraphicsImageRendererContext * _Nonnull rendererContext) {
        [gradientView drawViewHierarchyInRect:gradientView.bounds afterScreenUpdates:true];
    }];
斯威夫特4:

let renderer = UIGraphicsImageRenderer(size: gradientView.bounds.size)
        let image = renderer.image { ctx in
            gradientView.drawHierarchy(in: gradientView.bounds, afterScreenUpdates: true)
        }

我在我编写的示例项目中使用了此代码,这里是项目文件的链接:

SwiftObjective C

正如您将看到两个项目将在iPhone X上完美运行!

答案 2 :(得分:0)

我知道,以下听起来很奇怪。但是尝试使目标图像比您绘制的图像大一个像素。这解决了我(我的特殊问题:"[CALayer renderInContext]" crashes on iPhone X)。

在代码中:

UIGraphicsBeginImageContextWithOptions(
    CGSizeMake(viewToSave.image.size.width + 1, 
               viewToSave.image.size.height + 1), 
    viewToSave.opaque, 
    1.0
);

答案 3 :(得分:0)

总而言之,答案是最小的(不包括在问题中)细节......

iPhone X的比例因子等于@ 3x ,我真的没有考虑(并在很长一段时间后发现)。这是iPhone X和运行代码的所有其他设备之间的区别......

在我的代码中的某个时刻,我将子视图的.contentScaleFactor设置为等于[UIScreen mainScreen].scale。这意味着在高端设备上,图像质量应该更好。

对于iPhone X,[UIScreen mainScreen].scale返回3。 对于我测试过的所有其他设备,[UIScreen mainScreen].scale返回2.这意味着在iPhone X上,用于渲染图像的内存量会更高。

有趣的事实二:从another useful SO post,我发现在iPhone X上,如果你尝试分配超过50%的内存总量(1392 MB),它会崩溃。另一方面,例如,在iPhone 6s的情况下,百分比更高:68%(1396 MB)。 这意味着对于某些旧设备,您可以使用比使用iPhone X更多的设备。

对于误解,很抱歉,这是我的一个诚实的错误。谢谢大家的答案!