无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
相关产品推荐
相关产品推荐

