Swift应用:用户更新PDF后App无法识别的问题求助
问题分析与解决方案
Hey Eli, let's break down your problem and fix it step by step:
1. 关于更新后文件URL的疑问
如果用户修改的是你App沙盒内的同一个PDF文件,URL不会发生变化——因为文件路径是基于App的documentDirectory+文件名生成的,只要文件名不变,URL就保持一致。问题的核心不是URL变化,而是你的App没有正确读取文件的最新内容,或者路径构造逻辑存在错误。
2. 代码中的关键问题
问题1:didSelectRowAt中错误依赖全局变量
在导入文档的分支里,你用全局变量newDoc判断文件是否存在,但newDoc指向的是上一次导入的文件,而非当前选中的文件。这会导致路径构造错误,甚至加载旧的缓存内容。
问题2:PDF加载逻辑可能存在缓存
如果viewController.load()方法内部是通过文件名读取且缓存了PDF数据,即使文件内容更新,也不会重新加载最新版本。
问题3:重新导入时未处理文件覆盖
当前documentPicker方法中,如果同名文件已存在,moveItem会直接报错,导致新文件无法覆盖旧文件,删除后重新导入也无法获取最新内容。
3. 具体修复方案
修复方案1:修正didSelectRowAt的路径构造逻辑
直接根据当前选中的文件名构造正确URL,不再依赖全局变量:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { guard let navController = splitViewController?.viewControllers[1] as? UINavigationController else { return } guard let viewController = navController.viewControllers[0] as? ViewController else { return } let cell = tableView.cellForRow(at: indexPath) as! UITableViewCell let labelContent = cell.textLabel?.text print(labelContent as Any) //User tapped a built-in page if labelContent?.range(of:"✡️") != nil { fileIsFromService = false print ("It's a built-in page") guard let newURL = Bundle.main.url(forResource: items[indexPath.section][indexPath.row], withExtension: "pdf") else { return } path = newURL newBook = path.lastPathComponent print ("The url to be passed is \(path)") indexPoint = indexPath.row print ("indexPoint is now \(indexPoint)") viewController.load(from: newURL) } else { //User selected a document from the device's directory fileIsFromService = true indexPoint = indexPath.row let selectedFileName = items[indexPath.section][indexPath.row] let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let currentFileURL = documentDirectory.appendingPathComponent(selectedFileName) if FileManager.default.fileExists(atPath: currentFileURL.path) { path = currentFileURL newDoc = selectedFileName // 改成直接传递URL给ViewController,避免文件名歧义 viewController.load(from: currentFileURL) } else { print("Selected file no longer exists: \(selectedFileName)") // 可选:添加用户提示,告知文件已丢失 } } }
修复方案2:修改PDF加载逻辑,确保实时读取最新内容
在ViewController中更新load方法,直接从URL读取文件,不缓存旧内容:
// ViewController.swift func load(from fileURL: URL) { // 直接从URL读取最新的PDF数据 guard let pdfDocument = PDFDocument(url: fileURL) else { print("Failed to load PDF from URL: \(fileURL)") return } // 假设你用PDFView展示PDF pdfView.document = pdfDocument }
修复方案3:处理重新导入时的文件覆盖
更新documentPicker方法,先删除旧文件再移动新文件,确保覆盖成功:
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) { let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let destinationURL = documentDirectory.appendingPathComponent(url.lastPathComponent) do { // 如果目标文件已存在,先删除旧文件 if FileManager.default.fileExists(atPath: destinationURL.path) { try FileManager.default.removeItem(at: destinationURL) } try FileManager.default.moveItem(at: url.standardizedFileURL, to: destinationURL) } catch { print("Failed to move file: \(error)") return } finalDocURL = destinationURL newDoc = finalDocURL.lastPathComponent let isFileExist = items.joined().contains(newDoc) if !isFileExist { userDocs.append(newDoc) defaults.set(userDocs, forKey:"UserDocs") items[4].append(userDocs.last!) defaults.set(items, forKey:"Items") alertSuccess() } else { print("File overwritten successfully") // 文件已覆盖,刷新列表确保显示最新状态 tableView.reloadData() } tableView.reloadData() }
可选方案:实时监听文件变化
如果需要实时感知用户对PDF的修改,可以添加文件监听,自动刷新内容:
// 在ViewController中添加监听逻辑 var fileObserver: DispatchSourceFileSystemObject? func startObservingFile(at url: URL) { stopObservingFile() let fileDescriptor = open(url.path, O_EVTONLY) guard fileDescriptor != -1 else { print("Failed to open file for observation") return } fileObserver = DispatchSource.makeFileSystemObjectSource( fileDescriptor: fileDescriptor, eventMask: .write, queue: DispatchQueue.global() ) fileObserver?.setEventHandler { [weak self] in DispatchQueue.main.async { // 文件内容更新,重新加载 self?.load(from: url) } } fileObserver?.resume() } func stopObservingFile() { if let observer = fileObserver { observer.cancel() close(observer.handle) } fileObserver = nil } // 在页面消失时停止监听 override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) stopObservingFile() }
内容的提问来源于stack exchange,提问作者user3140521
相关产品推荐
相关产品推荐

