You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift技术问题:如何在NSObject类中调用pushViewController方法?

解决NSObject子类中调用navigationController跳转的问题

这个问题我之前也碰到过,核心就是你写的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:09:46