从详情ViewController返回后主视图未更新,viewDidLoad未触发如何处理?
解决从详情控制器返回后主视图不更新的问题
嘿,这个问题我碰到过好多次啦!之所以viewDidLoad()没触发,是因为主控制器早就加载完成了——viewDidLoad只会在控制器第一次创建、加载视图的时候调用一次,你从详情页dismiss回去的时候,主控制器的实例一直存在,自然不会再走这个方法啦。
下面给你几个常用的解决方案,按需选择就行:
方法一:利用viewWillAppear/viewDidAppear(最简单直接)
这两个方法会在控制器的视图即将显示/已经显示的时候被调用,不管是第一次加载还是从其他页面返回,都会触发。你只需要把更新主视图的代码移到这里就行:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) // 在这里写更新主视图的代码,比如刷新数据、更新UI控件 updateMainViewContent() } // 或者用viewDidAppear,看你的需求 override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // updateMainViewContent() }
如果只需要从详情页返回时才更新,不想每次显示都更新的话,可以加个标记:在主控制器present详情页的时候设置一个布尔值(比如shouldUpdateWhenBack = true),然后在viewWillAppear里判断,如果为true就更新,之后把标记设为false。
方法二:闭包回调(灵活可控)
在详情控制器里定义一个闭包,当点击返回按钮的时候调用这个闭包,主控制器在present详情页的时候给闭包赋值,在闭包里处理更新逻辑:
- 详情控制器代码:
class DetailViewController: UIViewController { // 定义闭包属性,可选类型 var updateMainViewClosure: (() -> Void)? @IBAction func backButtonClick(_ sender: UIButton) { // 调用闭包,通知主控制器更新 updateMainViewClosure?() dismiss(animated: true, completion: nil) } }
- 主控制器present详情页的代码:
let detailVC = DetailViewController() // 设置闭包,用[weak self]避免循环引用 detailVC.updateMainViewClosure = { [weak self] in guard let self = self else { return } // 在这里更新主视图 self.updateMainViewContent() } present(detailVC, animated: true, completion: nil)
方法三:代理模式(规范的iOS设计模式)
定义一个协议,让主控制器遵守这个协议,详情控制器持有代理对象,返回时调用代理方法:
- 定义协议(可放在详情控制器里):
protocol DetailViewControllerDelegate: AnyObject { func detailViewControllerDidDismiss(_ controller: DetailViewController) } class DetailViewController: UIViewController { // 代理对象,用weak避免循环引用 weak var delegate: DetailViewControllerDelegate? @IBAction func backButtonClick(_ sender: UIButton) { delegate?.detailViewControllerDidDismiss(self) dismiss(animated: true, completion: nil) } }
- 主控制器遵守协议并实现方法:
class MainViewController: UIViewController, DetailViewControllerDelegate { // ...其他代码 func presentDetailVC() { let detailVC = DetailViewController() detailVC.delegate = self present(detailVC, animated: true, completion: nil) } // 实现代理方法 func detailViewControllerDidDismiss(_ controller: DetailViewController) { // 更新主视图 updateMainViewContent() } }
方法四:通知中心(适合跨多个控制器传递消息)
如果你的场景比较复杂,或者需要多个控制器监听返回事件,可以用通知中心:
- 主控制器添加通知观察者:
override func viewDidLoad() { super.viewDidLoad() // 添加通知监听 NotificationCenter.default.addObserver(self, selector: #selector(updateMainView(_:)), name: NSNotification.Name("DetailDidDismissNotification"), object: nil) } @objc func updateMainView(_ notification: Notification) { // 更新主视图 updateMainViewContent() } // 记得在deinit里移除观察者,避免内存泄漏 deinit { NotificationCenter.default.removeObserver(self) }
- 详情控制器返回时发送通知:
@IBAction func backButtonClick(_ sender: UIButton) { // 发送通知 NotificationCenter.default.post(name: NSNotification.Name("DetailDidDismissNotification"), object: nil) dismiss(animated: true, completion: nil) }
以上几种方法里,方法一最适合简单场景,方法二和三适合一对一的控制器通信,方法四适合多对象监听的场景,你根据自己的需求选就好啦!
内容的提问来源于stack exchange,提问作者Marko
相关产品推荐
相关产品推荐

