iOS复用AddEditViewController时3D Touch传值失效问题求助
你遇到的核心问题是实例不匹配:你在Controller A中声明的controllerBref和3D Touch流程中实际弹出的AddEditViewController不是同一个对象。
当你在previewingContext(_:commitViewController:)里调用controllerBRef.setPreference(true)时,你修改的是自己手动创建的那个实例的属性,但系统在3D Touch提交时弹出的是你之前在previewingContext(_:viewControllerForLocation:)方法中返回的预览控制器实例——这两个是完全独立的对象,所以你设置的didPresentVia3dTouch不会同步到实际显示的Controller B上,自然在它的生命周期方法里值还是默认的false。
解决思路很简单:确保在3D Touch的预览阶段就把正确的模式设置到将要弹出的那个Controller B实例上,而不是操作一个无关的实例。
步骤1:修改预览控制器的创建逻辑
在previewingContext(_:viewControllerForLocation:)方法中,直接创建AddEditViewController实例并设置编辑模式,然后返回这个实例作为预览控制器:
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? { // 定位到触发3D Touch的cell guard let indexPath = tableView.indexPathForRow(at: location), let cell = tableView.cellForRow(at: indexPath) else { return nil } // 创建要预览的Controller B实例 let editVC = AddEditViewController() // 直接在这里设置3D Touch模式 editVC.setPreference(editMode: true) // 如果需要传递编辑的数据(比如当前cell对应的模型),也在这里完成 // editVC.targetModel = yourDataArray[indexPath.row] // 设置预览的触发区域为cell的frame previewingContext.sourceRect = cell.frame return editVC }
步骤2:简化commit方法
在previewingContext(_:commitViewController:)中,你不需要额外创建或修改实例——系统会自动将你之前返回的预览控制器模态弹出。如果没有特殊需求,这个方法可以简化为:
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commitViewController viewControllerToCommit: UIViewController) { // 系统已经帮你处理了弹出逻辑,这里如果需要额外操作(比如更新数据)可以加在这里 present(viewControllerToCommit, animated: true) }
步骤3:添加模式的处理
对于导航栏按钮触发的添加模式,你只需要在创建AddEditViewController时传入editMode: false即可:
@IBAction func addButtonTapped(_ sender: UIBarButtonItem) { let addVC = AddEditViewController() addVC.setPreference(editMode: false) present(addVC, animated: true) }
之前尝试代理没解决,大概率也是因为你把代理绑定到了自己声明的controllerBref上,而不是实际弹出的那个实例。现在按照上面的方式,所有实例都是在需要的时候创建并直接配置,就不会再出现属性不生效的问题了。
你可以在Controller B的viewWillAppear里打印didPresentVia3dTouch,现在应该能正确拿到对应的值,再根据这个值修改导航栏标题就没问题了。
内容的提问来源于stack exchange,提问作者Samarey

