SwiftUI中从已保存的SwiftData模型对象加载PDF时,PDFKit的go(:to)方法无法跳转页面
SwiftUI中从已保存的SwiftData模型对象加载PDF时,PDFKit的go(:to)方法无法跳转页面
我仔细看了你的代码、问题描述和视频,这个问题的核心原因大概率是PDF文档布局时机和你调用跳转代码的时机不匹配,再加上你当前用updateUIView+Coordinator的逻辑在从SwiftData加载时的执行条件有漏洞。
先拆解下问题:
当你通过"Add PDF"按钮导入PDF时,新创建的PDF对象是刚生成的,PDFKitView2初始化后,updateUIView执行时PDF文档刚好完成了初始布局,所以go(to:page)能正常生效。但从列表打开已保存的PDF时,SwiftData的PDF对象是从持久化存储读取的,PDFView加载文档的布局会慢半拍——当你的updateUIView里的代码执行时,PDF的页面还没完全准备好,这时候调用go(to:)自然就失效了。
另外你原来代码里的DispatchQueue.main.async是多余的,updateUIView本身就在主队列执行,这个异步调用反而可能让跳转代码在文档布局完成前就跑了,进一步加剧了时机问题。
给你一个可靠的修复方案:利用PDFViewDelegate的回调,等PDF文档完全布局好之后再执行跳转,这样不管是首次导入还是从列表加载,都能保证跳转时机正确。
修改后的PDFKitView2代码如下:
struct PDFKitView2: UIViewRepresentable { let pdf: PDF func makeUIView(context: Context) -> PDFView { let pdfView = PDFView() pdfView.document = PDFDocument(data: pdf.data) pdfView.autoScales = true pdfView.pageShadowsEnabled = false // 将Coordinator设为PDFView的代理 pdfView.delegate = context.coordinator return pdfView } func updateUIView(_ uiView: PDFView, context: Context) { // 这里可以保留其他视图更新逻辑,跳转逻辑移到代理回调里 } func makeCoordinator() -> Coordinator { Coordinator(self) } class Coordinator: NSObject, PDFViewDelegate { var parent: PDFKitView2 // 标记只执行一次跳转,避免重复触发 var shouldJumpToPage: Bool = true init(_ parent: PDFKitView2) { self.parent = parent super.init() } // 这个回调会在PDF文档完全布局完成、所有页面就绪后触发 func pdfViewDidLayoutDocument(_ pdfView: PDFView) { guard shouldJumpToPage, let targetPage = pdfView.document?.page(at: 2) else { return } pdfView.go(to: targetPage) shouldJumpToPage = false } } }
为什么这个方案能解决问题?
- 我们让Coordinator遵守
PDFViewDelegate,并监听pdfViewDidLayoutDocument回调——这个方法是PDFKit专门用来通知开发者文档布局完成的信号,这时候调用页面跳转是最稳妥的。 - 用
shouldJumpToPage标记只执行一次跳转,避免后续文档布局变化(比如用户缩放页面)时重复触发跳转。 - 去掉了多余的异步调用,完全跟着PDFKit的生命周期走,从根源上避免了时机不匹配的问题。
另外你不用担心SwiftData的data保存问题——从列表打开时PDF能正常显示,说明数据是完整的,不用怀疑数据损坏的问题。
你可以测试下修改后的代码,不管是从导入流程打开还是从列表打开已保存的PDF,都应该能正确跳转到第2页了。
内容来源于stack exchange
相关产品推荐
相关产品推荐

