繁体   English   中英

iPhone X上的“ [CALayer renderInContext]”崩溃

[英]“[CALayer renderInContext]” crashes on 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个圆圈作为子视图:

内存分配(堆+匿名VM)

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

不幸的是,我没有iPhone X的访问权限,而报告此举的人也没有Mac的访问权限,因此我无法进行更深入的研究。

我真的不知道我做错什么了吗...您知道iPhone X是否有所不同吗? 我已经为这个问题苦苦挣扎了一段时间了...

我想这个问题与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;
}

我最近在我制作的应用程序中编写了一种方法,用于将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)
        }

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

斯威夫特目标C

如您所见,这两个项目都将在iPhone X上完美运行!

我知道,以下听起来很奇怪。 但是,请尝试使目标图像比要绘制的像素大一像素。 这为我解决了(我的特殊问题: “ [CALayer renderInContext]”在iPhone X上崩溃 )。

在代码中:

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

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

我真的没有考虑过(不久后才发现), iPhone X的缩放系数等于@ 3x 这就是iPhone X和其他所有正在运行该代码的设备之间的区别...

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

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

有趣的事实二:从另一篇有用的SO文章中 ,我发现在iPhone X上,如果您尝试分配的内存总量(1392 MB)超过50%,则会崩溃。 另一方面,例如,在iPhone 6s的情况下,百分比更高:68%(1396 MB)。 这意味着与iPhone X相比,对于某些较旧的设备,您拥有更多的工作记忆。

对不起,我误导了我,这是一个诚实的错误。 谢谢大家的答案!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM