将UIView转为图片时内存飙升致APP崩溃的问题求助
横向长图分割预览时内存溢出崩溃的解决方案
我的ScrollView内有一个横向UIView,包含多张大尺寸图片,需将其分割为轮播帖规格的预览图,但执行生成预览的函数时APP因内存不足崩溃,排查确认是渲染预览阶段内存占用过高。
原实现代码
生成预览图函数
func generatePreviewImages() -> [UIImage] { let arrMaskView = properties.arrAllObjectView.filter({ ($0 as? MaskView) != nil }) as? [MaskView] ?? [MaskView]() arrMaskView.forEach({ $0.imageViewAddIcon.isHidden = true }) var arrImage = [UIImage]() for i in 0..<Int(properties.cols) { autoreleasepool(invoking: { let x = (viewCanvas.frame.size.width / properties.cols.cgFloat) * CGFloat(i) let width = (viewCanvas.frame.size.width / properties.cols.cgFloat) if let image = viewCanvas.asImage(bounds: CGRect.init(x: x, y: 0, width: width, height: viewCanvas.bounds.height)) { arrImage.append(image) } }) } arrMaskView.forEach({ $0.imageViewAddIcon.isHidden = !($0.imageUser == nil) }) return arrImage }
UIView转图片函数
func asImage(bounds:CGRect) -> UIImage? { let renderer = UIGraphicsImageRenderer(bounds: bounds) return renderer.image { rendererContext in layer.render(in: rendererContext.cgContext) } }
优化方案
1. 跳过UIView渲染,直接裁剪原始图片
原方案每次分割都渲染整个大View,会重复加载全量大图到内存。若能直接获取原始图片资源,优先使用UIImage原生裁剪API,避免UI渲染开销:
// 从原始大图裁剪指定区域(适配UIImage坐标系) func cropImage(from originalImage: UIImage, to targetRect: CGRect) -> UIImage? { guard let cgImage = originalImage.cgImage else { return nil } let scale = originalImage.scale // 转换UIKit坐标系到CGImage坐标系,并适配缩放因子 let cropRect = CGRect( x: targetRect.origin.x * scale, y: (originalImage.size.height - targetRect.origin.y - targetRect.height) * scale, width: targetRect.width * scale, height: targetRect.height * scale ) guard let croppedCGImage = cgImage.cropping(to: cropRect) else { return nil } return UIImage(cgImage: croppedCGImage, scale: scale, orientation: originalImage.imageOrientation) }
2. 优化UIView渲染逻辑
若必须从UIView生成图片,需避免渲染整个View,只渲染目标区域,并降低预览图分辨率:
// 优化后的UIView转图片函数,支持指定缩放因子和裁剪区域 func asImage(bounds: CGRect, scale: CGFloat = UIScreen.main.scale * 0.5) -> UIImage? { let format = UIGraphicsImageRendererFormat() format.scale = scale // 降低缩放因子减少像素量,根据预览需求调整 let renderer = UIGraphicsImageRenderer(bounds: bounds, format: format) return renderer.image { context in context.saveGState() // 只裁剪并渲染目标区域 context.clip(to: bounds) context.translateBy(x: -bounds.origin.x, y: -bounds.origin.y) layer.render(in: context.cgContext) context.restoreGState() } }
3. 按需生成预览图
不要一次性生成所有预览图,而是结合轮播控件的滚动事件,按需生成并缓存已生成的预览图,避免同时持有大量图片实例。
4. 强化内存管理
- 确保生成的预览图为
CGImage-backed类型,避免CIImage带来的额外内存开销 - 生成预览后及时释放原始大图的强引用
- 保留
autoreleasepool包裹单张图片的生成逻辑,确保临时对象及时回收
内容的提问来源于stack exchange,提问作者Kamlesh Shingarakhiya
相关产品推荐
相关产品推荐

