iOS13中Sheet关闭后如何刷新前一个ViewController?
解决iOS13中Sheet关闭后刷新前一个ViewController的问题
这个问题我之前也碰到过!iOS13之后,系统默认的模态呈现样式改成了UIModalPresentationStyle.pageSheet,这种情况下,被present的Sheet只是覆盖在原ViewController的视图上面,原VC的视图并没有被移除或隐藏,所以viewWillAppear、viewDidLoad这些生命周期方法自然不会被触发。下面给你几种实用的解决方案,按需选择即可:
方法1:闭包(Closure)—— 简单直接,适合轻量场景
闭包是最简单的实现方式,不需要额外定义协议,适合只需要通知原VC刷新、不需要传递复杂数据的场景。
步骤1:在设置ViewController中定义闭包属性
class SettingsViewController: UIViewController { // 定义一个可选闭包,用于通知原VC执行刷新操作 var onDismiss: (() -> Void)? // 假设这是关闭按钮的点击事件 @IBAction func closeButtonTapped(_ sender: UIButton) { dismiss(animated: true) { // 在Sheet完全关闭后调用闭包 self.onDismiss?() } } }
步骤2:在原ViewController中present时绑定闭包
class MainViewController: UIViewController { // 触发present设置页的方法 @IBAction func showSettingsTapped(_ sender: UIButton) { guard let settingsVC = storyboard?.instantiateViewController(withIdentifier: "SettingsViewController") as? SettingsViewController else { return } // 绑定闭包,注意用[weak self]避免循环引用 settingsVC.onDismiss = { [weak self] in self?.refreshCurrentView() } present(settingsVC, animated: true) } // 自定义的刷新视图方法 private func refreshCurrentView() { // 这里写你的刷新逻辑,比如重新加载数据、更新UI控件 tableView.reloadData() // ...其他操作 } }
方法2:代理(Delegate)—— 适合需要传递数据的复杂场景
如果你的设置页需要把用户修改的设置数据回传给原VC,代理模式会更清晰、更易于维护。
步骤1:定义代理协议
// 定义代理协议,注意用AnyObject确保只能被类遵守 protocol SettingsViewControllerDelegate: AnyObject { // 可以根据需求添加参数,比如传递修改后的设置数据 func settingsViewControllerDidFinish(_ controller: SettingsViewController, updatedSettings: UserSettings?) }
步骤2:在设置ViewController中添加代理属性
class SettingsViewController: UIViewController { // 弱引用代理,避免循环引用 weak var delegate: SettingsViewControllerDelegate? // 假设这是用户修改后的设置数据 private var updatedSettings: UserSettings? @IBAction func closeButtonTapped(_ sender: UIButton) { dismiss(animated: true) { // 通知代理刷新,并传递数据 self.delegate?.settingsViewControllerDidFinish(self, updatedSettings: self.updatedSettings) } } }
步骤3:原ViewController遵守并实现代理方法
class MainViewController: UIViewController, SettingsViewControllerDelegate { @IBAction func showSettingsTapped(_ sender: UIButton) { guard let settingsVC = storyboard?.instantiateViewController(withIdentifier: "SettingsViewController") as? SettingsViewController else { return } settingsVC.delegate = self present(settingsVC, animated: true) } // 实现代理方法 func settingsViewControllerDidFinish(_ controller: SettingsViewController, updatedSettings: UserSettings?) { // 先处理回传的数据,再刷新视图 if let settings = updatedSettings { // 保存设置数据 UserDefaults.standard.set(settings.isDarkMode, forKey: "DarkMode") } // 执行刷新 refreshCurrentView() } private func refreshCurrentView() { // 刷新逻辑 } }
方法3:监听Sheet的自动关闭(比如下拉关闭)
如果你的Sheet允许用户通过下拉手势直接关闭(pageSheet默认支持),上面两种方法可能不会触发(因为用户没点击关闭按钮),这时候可以用UIAdaptivePresentationControllerDelegate来监听Sheet的关闭事件。
实现步骤
class MainViewController: UIViewController, UIAdaptivePresentationControllerDelegate { @IBAction func showSettingsTapped(_ sender: UIButton) { guard let settingsVC = storyboard?.instantiateViewController(withIdentifier: "SettingsViewController") as? SettingsViewController else { return } // 设置presentationController的代理 settingsVC.presentationController?.delegate = self present(settingsVC, animated: true) } // 当Sheet被任何方式关闭时都会调用这个方法 func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { refreshCurrentView() } private func refreshCurrentView() { // 刷新逻辑 } }
你可以把这个方法和闭包/代理结合使用,确保无论用户是点击按钮还是下拉关闭,都能触发刷新。
方法4:通知中心(NotificationCenter)—— 尽量少用,适合跨多层VC的场景
通知中心的耦合度比较高,不好维护,除非你的刷新逻辑需要跨多个不相关的VC,否则不推荐使用。
步骤1:原ViewController添加通知观察者
class MainViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // 添加通知观察者 NotificationCenter.default.addObserver(self, selector: #selector(refreshCurrentView), name: NSNotification.Name("SettingsDidDismiss"), object: nil) } deinit { // 一定要在销毁时移除观察者,避免内存泄漏 NotificationCenter.default.removeObserver(self) } @objc private func refreshCurrentView() { // 刷新逻辑 } }
步骤2:设置ViewController关闭时发送通知
class SettingsViewController: UIViewController { @IBAction func closeButtonTapped(_ sender: UIButton) { dismiss(animated: true) { // 发送通知 NotificationCenter.default.post(name: NSNotification.Name("SettingsDidDismiss"), object: nil) } } }
内容的提问来源于stack exchange,提问作者developer16
相关产品推荐
相关产品推荐

