UISplitViewController主视图控制器rightBarButtonItem点击无响应问题
问题:UISplitViewController主列导航栏按钮点击无响应
用户代码
IpadLayoutCoordinator
class IpadLayoutCoordinator: BaseCoordinator { private let rootViewController: UINavigationController private lazy var splitVC: UISplitViewController = { let vc = UISplitViewController(style: .doubleColumn) vc.minimumPrimaryColumnWidth = 450.0 vc.maximumPrimaryColumnWidth = 450.0 return vc }() init(navController: UINavigationController) { self.rootViewController = navController } override func start() { let primaryViewCoordinator = PrimaryViewCoordinator(rootView: splitVC) primaryViewCoordinator.start() self.parentCoordinator?.store(coordinator: primaryViewCoordinator) let secondaryView = UIViewController() secondaryView.view.backgroundColor = .blueColor splitVC.setViewController(secondaryView, for: .secondary) let containerVC = UIViewController() containerVC.addChildViewController(splitVC, toView: containerVC.view) rootViewController.setViewControllers([containerVC], animated: true) } }
PrimaryViewCoordinator
class PrimaryViewCoordinator: BaseCoordinator { private let rootViewController: UISplitViewController private lazy var primaryVC: PrimaryViewController = { let vc = PrimaryViewController.loadFromNib() /* This is the button not working */ let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(self.goToAddVC)) vc.navigationItem.rightBarButtonItem = addButton return vc }() init(rootView: UISplitViewController) { self.rootViewController = rootView } override func start() { rootViewController.setViewController(primaryVC, for: .primary) } @objc private func goToAddVC() { /* This is the action not working */ let addItemCoordinator = AddItemCoordinator(rootView: rootViewController) addItemCoordinator.start() self.store(coordinator: addItemCoordinator) } }
问题原因
核心问题是PrimaryViewCoordinator实例被提前释放:
- 在
IpadLayoutCoordinator的start方法中,primaryViewCoordinator是局部变量,尽管调用了self.parentCoordinator?.store(coordinator: primaryViewCoordinator),但如果BaseCoordinator的store方法没有强引用子协调器,或者parentCoordinator的引用链存在问题,这个实例会在方法执行完毕后被ARC回收。 - 导航栏按钮的
target指向PrimaryViewCoordinator实例,当实例被释放后,点击事件找不到接收者,自然无法触发goToAddVC方法。
修复方案
方案1:在IpadLayoutCoordinator中强引用子协调器
修改IpadLayoutCoordinator,添加属性持有primaryViewCoordinator,避免其被释放:
class IpadLayoutCoordinator: BaseCoordinator { private let rootViewController: UINavigationController // 添加强引用属性 private var primaryViewCoordinator: PrimaryViewCoordinator? private lazy var splitVC: UISplitViewController = { let vc = UISplitViewController(style: .doubleColumn) vc.minimumPrimaryColumnWidth = 450.0 vc.maximumPrimaryColumnWidth = 450.0 return vc }() init(navController: UINavigationController) { self.rootViewController = navController } override func start() { let coordinator = PrimaryViewCoordinator(rootView: splitVC) coordinator.start() self.primaryViewCoordinator = coordinator // 强引用保存 self.parentCoordinator?.store(coordinator: coordinator) let secondaryView = UIViewController() secondaryView.view.backgroundColor = .blueColor splitVC.setViewController(secondaryView, for: .secondary) let containerVC = UIViewController() containerVC.addChildViewController(splitVC, toView: containerVC.view) rootViewController.setViewControllers([containerVC], animated: true) } }
方案2:确保BaseCoordinator的store方法正确强引用子协调器
检查BaseCoordinator的实现,确保它通过数组强引用子协调器:
class BaseCoordinator { var childCoordinators = [BaseCoordinator]() func store(coordinator: BaseCoordinator) { childCoordinators.append(coordinator) } // 可选:添加移除方法避免内存泄漏 func free(coordinator: BaseCoordinator) { childCoordinators.removeAll { $0 === coordinator } } func start() { // 子类实现 } weak var parentCoordinator: BaseCoordinator? }
之后修改IpadLayoutCoordinator的start方法,让当前协调器直接持有子协调器:
override func start() { let primaryViewCoordinator = PrimaryViewCoordinator(rootView: splitVC) primaryViewCoordinator.start() self.store(coordinator: primaryViewCoordinator) // 当前协调器持有 // self.parentCoordinator?.store(coordinator: primaryViewCoordinator) 可按需保留或移除 // ... 其余代码不变 }
额外检查点
- 确认
PrimaryViewController的navigationItem没有被nib文件或其他代码覆盖,导致代码添加的按钮被替换。 - 若
primaryVC未被包裹在UINavigationController中,可尝试将其包裹后再设置给splitVC:
override func start() { let navVC = UINavigationController(rootViewController: primaryVC) rootViewController.setViewController(navVC, for: .primary) }
内容的提问来源于stack exchange,提问作者helpinghand
相关产品推荐
相关产品推荐

