Swift技术问题:如何在NSObject类中调用pushViewController方法?
这个问题我之前也碰到过,核心就是你写的SlideMenuLauncher作为NSObject子类,本身没有持有导航控制器的引用,所以没法直接调用pushViewController。下面给你几个实用的解决方案,按需选择:
方案1:直接持有导航控制器引用
最简单的方式就是给你的SlideMenuLauncher添加一个navigationController属性,初始化的时候把当前的导航控制器传进去。注意要用weak修饰,避免循环引用导致内存泄漏:
import UIKit class SlideMenuLauncher: NSObject, UITableViewDelegate, UITableViewDataSource { // 用weak修饰防止循环引用 weak var navigationController: UINavigationController? // 初始化时传入导航控制器 init(navigationController: UINavigationController?) { self.navigationController = navigationController super.init() } // 你的其他tableView数据源、代理方法... func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) // 示例:跳转到目标页面 let targetVC = TargetViewController() navigationController?.pushViewController(targetVC, animated: true) } } // 在创建SlideMenuLauncher的地方传入导航控制器: // let menuLauncher = SlideMenuLauncher(navigationController: self.navigationController)
方案2:用闭包回调解耦
如果不想让SlideMenuLauncher直接依赖导航控制器,闭包是个很好的选择——把跳转逻辑交给创建菜单的ViewController来处理,解耦性更强:
import UIKit class SlideMenuLauncher: NSObject, UITableViewDelegate, UITableViewDataSource { // 定义闭包类型,可根据需求调整参数(比如传入菜单类型、索引等) var onMenuItemSelected: ((Int) -> Void)? // 你的其他代码... func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) // 触发闭包,把选中的索引传递出去 onMenuItemSelected?(indexPath.row) } } // 在创建菜单的ViewController中处理跳转: class MainViewController: UIViewController { func setupSlideMenu() { let menuLauncher = SlideMenuLauncher() // 绑定闭包,处理跳转逻辑 menuLauncher.onMenuItemSelected = { [weak self] selectedIndex in guard let self = self else { return } switch selectedIndex { case 0: let profileVC = ProfileViewController() self.navigationController?.pushViewController(profileVC, animated: true) case 1: let settingVC = SettingViewController() self.navigationController?.pushViewController(settingVC, animated: true) default: break } } // 其他菜单初始化逻辑... } }
方案3:代理模式(适合复杂场景)
如果菜单的交互逻辑比较复杂,代理模式会更清晰,扩展性也更好:
import UIKit // 定义代理协议 protocol SlideMenuDelegate: AnyObject { func slideMenuDidSelectItem(at index: Int) } class SlideMenuLauncher: NSObject, UITableViewDelegate, UITableViewDataSource { // 代理对象用weak修饰,避免循环引用 weak var delegate: SlideMenuDelegate? // 你的其他代码... func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) // 通知代理处理选中事件 delegate?.slideMenuDidSelectItem(at: indexPath.row) } } // 在ViewController中遵守并实现代理: class MainViewController: UIViewController, SlideMenuDelegate { func setupSlideMenu() { let menuLauncher = SlideMenuLauncher() menuLauncher.delegate = self // 其他菜单初始化逻辑... } // 实现代理方法,处理跳转 func slideMenuDidSelectItem(at index: Int) { switch index { case 0: let vc = HomeViewController() navigationController?.pushViewController(vc, animated: true) // 更多菜单选项处理... default: break } } }
小建议
如果只是简单的跳转需求,方案1足够用;如果想让代码解耦、更易维护,优先选方案2或3,尤其是闭包的方式代码更简洁~
内容的提问来源于stack exchange,提问作者UK4
相关产品推荐
相关产品推荐

