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

无Embed Segue时如何让容器ViewController遵循自定义协议?

纯代码实现容器ViewController的协议遵循检查与引用传递

核心问题分析

你之前的代码错误在于创建了新的HomeViewController实例,而不是引用当前已经存在的容器ViewController实例。子VC需要持有对父容器VC的协议引用,而非新建一个无关的实例。

正确实现步骤

1. 确保容器VC遵循协议

首先保证HomeViewController正确遵循MoodsConfigurable协议并实现所有要求的方法:

// 定义协议,声明为AnyObject以支持弱引用
protocol MoodsConfigurable: AnyObject {
    func moodSelected(_ mood: Mood) // 示例协议方法,根据你的需求调整
    // 其他协议方法...
}

class HomeViewController: UIViewController, MoodsConfigurable {
    // 实现协议要求的所有方法
    func moodSelected(_ mood: Mood) {
        // 这里写你的业务逻辑,比如响应子VC的情绪选择事件
    }
}

2. 在容器VC中管理子VC并传递协议引用

在HomeViewController中完成子UITableViewController的实例化、添加容器流程,并做协议检查:

class HomeViewController: UIViewController, MoodsConfigurable {
    // 持有子VC的引用
    private let moodsTableVC = MoodsTableViewController()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setupChildTableViewController()
    }
    
    private func setupChildTableViewController() {
        // 运行期断言检查:确保当前容器VC遵循协议(编译期也会检查,但断言能在开发阶段快速暴露问题)
        guard let configurableContainer = self as? MoodsConfigurable else {
            preconditionFailure("HomeViewController must conform to MoodsConfigurable")
        }
        
        // 将容器VC的协议引用传递给子VC,用weak避免循环引用
        moodsTableVC.moodsConfigurable = configurableContainer
        
        // 纯代码添加子VC的标准流程
        addChild(moodsTableVC)
        // 给子VC的view设置布局:可用frame或Auto Layout约束,示例用frame占满容器
        moodsTableVC.view.frame = view.bounds
        view.addSubview(moodsTableVC.view)
        moodsTableVC.didMove(toParent: self)
        
        // 对应原Storyboard示例中的安全区域设置
        moodsTableVC.additionalSafeAreaInsets = UIEdgeInsets(top: 0, left: 0, bottom: 160, right: 0)
    }
    
    // 实现协议方法...
    func moodSelected(_ mood: Mood) {
        // 处理逻辑
    }
}

3. 子UITableViewController中使用协议引用

在你的UITableViewController子类中,声明弱引用的协议属性,并在需要时调用协议方法:

class MoodsTableViewController: UITableViewController {
    // 用weak修饰,避免容器VC和子VC之间的循环引用
    weak var moodsConfigurable: MoodsConfigurable?
    
    // 示例:点击Cell时调用协议方法
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let selectedMood = yourMoodDataArray[indexPath.row]
        // 可选链式调用确保安全,避免nil崩溃
        moodsConfigurable?.moodSelected(selectedMood)
    }
}

关键注意事项

  • 协议必须声明为AnyObject:这样才能让子VC用weak修饰协议属性,避免容器VC(持有子VC)和子VC(持有容器协议引用)之间的循环引用导致内存泄漏。
  • 运行期断言preconditionFailure:在开发阶段强制检查协议遵循,一旦容器VC未实现协议,会直接崩溃并给出明确提示,比打印日志更能快速定位问题。
  • 纯代码添加子VC的标准流程:必须调用addChild(_:)、didMove(toParent:),确保ViewController的生命周期方法正确触发。

内容的提问来源于stack exchange,提问作者mrdb10

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 04:20:32