iOS 16下PDFView设置autoScales=true导致应用冻结问题求助
iOS 16下使用PDFView展示图片触发缩放断言错误导致应用冻结
问题描述
我在SwiftUI应用中用PDFView展示图片来实现捏合缩放功能,iOS 15上运行正常,但升级到iOS 16后,加载PhotoDetailView时应用直接冻结,模拟器和真机都出现这个问题。
代码示例
import SwiftUI import PDFKit struct PhotoDetailView: UIViewRepresentable { let image: UIImage func makeUIView(context: Context) -> PDFView { let view = PDFView() view.document = PDFDocument() guard let page = PDFPage(image: image) else { return view } view.document?.insert(page, at: 0) view.autoScales = true return view } func updateUIView(_ uiView: PDFView, context: Context) { // empty } }
错误日志
在iOS 16.0模拟器运行时,控制台输出两个错误:
[Assert] -[UIScrollView _clampedZoomScale:allowRubberbanding:]: Must be called with non-zero scale[Unknown process name] CGAffineTransformInvert: singular matrix.
已做排查
我定位到问题出在view.autoScales = true:设置该属性前view.scaleFactor为1.0,设置后直接变成0.0,这正是触发错误的原因。iOS 15模拟器也会输出这些错误,但图片仍能正常加载;注释掉view.autoScales = true后,图片可以加载,但尺寸远大于设备屏幕。
我想避免构建自定义图片查看器,只需要实现基础的捏合缩放功能,请问该如何解决?
解决方案
方案1:延迟设置autoScales属性
iOS 16中PDFView对autoScales的设置时机要求更严格,在视图未完成布局时直接设置会导致缩放比例计算异常。我们可以通过DispatchQueue.main.async延迟设置该属性,让视图先完成初始化布局:
func makeUIView(context: Context) -> PDFView { let view = PDFView() view.document = PDFDocument() guard let page = PDFPage(image: image) else { return view } view.document?.insert(page, at: 0) // 延迟到主队列下一轮循环设置autoScales,确保视图已完成布局 DispatchQueue.main.async { view.autoScales = true } return view }
方案2:手动计算初始缩放比例(更稳定)
如果延迟设置仍有问题,可以手动计算适配屏幕的初始缩放比例,同时配置缩放范围,替代autoScales的自动适配逻辑:
func makeUIView(context: Context) -> PDFView { let view = PDFView() view.document = PDFDocument() guard let page = PDFPage(image: image) else { return view } view.document?.insert(page, at: 0) // 设置缩放范围,满足捏合缩放需求 view.minScaleFactor = 0.1 view.maxScaleFactor = 5.0 // 手动计算适配当前视图尺寸的缩放比例 view.scaleFactor = view.scaleFactorForSizeToFit return view }
问题原因
iOS 16对UIScrollView的缩放逻辑做了更严格的断言检查,当PDFView在未完成布局时设置autoScales = true,内部计算缩放比例时会出现零值,触发UIScrollView的断言错误,进而导致应用冻结。而iOS 15虽然会输出错误日志,但系统容错机制没有让应用崩溃或冻结。
内容的提问来源于stack exchange,提问作者jus10
相关产品推荐
相关产品推荐

