簡體   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