如何在UISplitViewController的主视图与详情视图间共享数据模型?
解决UISplitViewController中主/详情视图共享DataModelController实例的问题
我来帮你搞定这个共享数据模型的问题~针对你的SplitViewController架构,有几个实用的实现方式,我给你逐个拆解:
方法一:通过SplitViewController直接传递引用
因为主视图(master)和详情视图(detail)都是SplitViewController的子控制器,你可以在主视图里拿到SplitViewController的引用,再找到详情页的控制器,把dataModelController实例传过去。
方式1:在主视图的生命周期方法中传递
在NotePreviewCollectionViewController里,比如视图加载完成后,主动给详情页赋值:
class NotePreviewCollectionViewController: UICollectionViewController { let dataModelController = DataModelController() override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // 先拿到SplitViewController guard let splitVC = self.splitViewController else { return } // 从SplitViewController的子控制器中找到详情导航页,再拿到里面的PageViewController if let detailNav = splitVC.viewControllers.last as? UINavigationController, let pageVC = detailNav.topViewController as? PageViewController { // 把主视图的dataModelController传给详情页 pageVC.dataModelController = self.dataModelController } } }
方式2:通过Segue跳转时传递
如果你的详情页是通过Segue跳转打开的,那可以在prepare(for:sender:)方法里直接传递实例:
class NotePreviewCollectionViewController: UICollectionViewController { let dataModelController = DataModelController() override func prepare(for segue: UIStoryboardSegue, sender: Any?) { // 先判断Segue的标识(记得在Storyboard里给Segue设置好identifier) guard segue.identifier == "ShowDetailPage", let pageVC = segue.destination as? PageViewController else { return } // 传递共享实例 pageVC.dataModelController = self.dataModelController } }
方法二:依赖注入(更推荐,解耦性更强)
这种方式是把DataModelController的实例创建在更高层级(比如SceneDelegate/AppDelegate),然后分别注入给主视图和详情视图,这样两个视图都从同一个源头拿到实例,互相不依赖,代码更灵活。
步骤1:修改主视图的属性定义
把主视图里的let改成var,等待外部注入:
class NotePreviewCollectionViewController: UICollectionViewController { var dataModelController: DataModelController! // 改为var,由外部赋值 }
步骤2:在SceneDelegate中创建并注入实例
iOS 13+使用SceneDelegate,在场景初始化时完成注入:
class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } let window = UIWindow(windowScene: windowScene) self.window = window // 创建唯一的共享DataModelController实例 let sharedDataModel = DataModelController() // 获取根视图的SplitViewController guard let splitVC = window.rootViewController as? UISplitViewController else { return } // 给主视图注入实例 if let masterNav = splitVC.viewControllers.first as? UINavigationController, let masterVC = masterNav.topViewController as? NotePreviewCollectionViewController { masterVC.dataModelController = sharedDataModel } // 给详情视图注入实例 if let detailNav = splitVC.viewControllers.last as? UINavigationController, let detailVC = detailNav.topViewController as? PageViewController { detailVC.dataModelController = sharedDataModel } window.makeKeyAndVisible() } }
方法三:单例模式(简单但要注意适用场景)
如果你的DataModelController不需要频繁销毁重建,生命周期和App一致,那可以把它做成单例,这样任何地方都能直接拿到同一个实例。
步骤1:修改DataModelController为单例
class DataModelController { // 全局共享的单例实例 static let shared = DataModelController() // 私有化初始化方法,禁止外部创建新实例 private init() {} // 你的其他业务方法和属性... }
步骤2:在两个视图控制器中使用
// PageViewController里直接引用 class PageViewController: UIViewController { var dataModelController = DataModelController.shared } // NotePreviewCollectionViewController里直接引用 class NotePreviewCollectionViewController: UICollectionViewController { let dataModelController = DataModelController.shared }
⚠️ 注意:单例是全局持久存在的,如果你需要在某些场景下销毁数据模型,这种方式就不太适合,优先考虑前面的依赖注入方式。
内容的提问来源于stack exchange,提问作者Hannes Richter
相关产品推荐
相关产品推荐

