SwiftUI 基础:使用 @StateObject、@ObservedObject 和 @EnvironmentObject 配合 NavigationPath 管理复杂导航(MVVM 模式)
一、目标
在本节中,我们将深入了解 SwiftUI 中的三种状态管理方式:@StateObject、@ObservedObject 和 @EnvironmentObject,并学习如何在复杂的应用中使用这些工具来高效管理视图间的数据共享与更新,实现多级页面间的任意跳转,一键返回首页
MVVM模式
二、SwiftUI 状态管理简介
SwiftUI 提供了多种方式来管理状态和数据绑定,这些机制适用于不同的场景:
@StateObject是SwiftUI中用于在视图中拥有和初始化一个ObservableObject的属性包装器。当视图重新创建时,@StateObject保证对象不会被重新初始化,从而确保状态的持久。@ObservedObject用于订阅并监听由其他视图或对象管理的状态,不会拥有该对象,因此适合在子视图中使用。@EnvironmentObject提供了一种将状态对象注入到整个视图层级的方法,无需显式传递。适用于多个视图共享同一个状态对象的场景
可能会遇到的问题及注意事项
- 状态对象未被初始化:
- 错误:Fatal error: No ObservableObject of type … found
- 解决方案:确保在父视图中使用
.environmentObject()注入
- 多次初始化对象:
- 错误:使用
@StateObject导致意外行为 - 解决方案:确保只在状态对象的拥有者使用
@StateObject,子视图使用@ObservedObject
- 错误:使用
- 跨多个视图共享状态:
- 推荐使用:@EnvironmentObject
三、NavigationPath简介
在
SwiftUI中,NavigationPath是一种用于管理页面导航历史和堆栈的结构体,允许开发者更灵活地控制导航堆栈的状态。
它是 iOS 16 引入的一个重要新特性,与传统的NavigationLink相比,NavigationPath提供了更强大的功能,尤其在处理复杂的导航场景时
主要特点:
- 动态管理导航堆栈。
NavigationPath可以保存多个页面的导航历史,让开发者能够自由地进行导航堆栈的操作。 - 与
NavigationStack。它通常与NavigationStack结合使用,通过绑定NavigationPath来控制页面的导航历史。NavigationStack会自动根据NavigationPath中的内容来显示相应的视图。 - 支持类型安全的导航。与传统的
NavigationLink不同,NavigationPath允许开发者通过使用不同的目标类型(例如枚举类型)来管理跳转的页面,使得导航更具类型安全性和可维护性。
使用方法,参考官方文档:

四、ViewModel简介
在
SwiftUI的开发中,ViewModel是实现MVVM(Model-View-ViewModel)设计模式的核心部分,用于管理视图的状态和业务逻辑。它在视图(View)和数据(Model)之间起到桥梁作用,将数据的处理逻辑从视图中抽离出来,使代码更清晰、更易于维护。
1. ViewModel 的作用、优点
- 管理状态
ViewModel持有视图需要的所有状态,并通过绑定(Binding)将状态与视图连接。状态发生变化时,SwiftUI自动更新相关视图
- 处理业务逻辑
-ViewModel负责封装视图相关的业务逻辑,如网络请求、数据验证等,从而让视图专注于 UI 渲染 - 隔离视图和数据
-ViewModel解耦了视图与模型(Model),视图无需直接操作模型数据,而是通过ViewModel获取所需的数据 - 便于测试
- 因为ViewModel不依赖于具体的视图,实现单元测试更加方便
2.ViewModel 的特点
- 遵循
ObservableObject协议
-SwiftUI的视图与ViewModel通信通常依赖@Published属性和ObservableObject协议
- 当ViewModel中的@Published属性值发生变化时,绑定该属性的视图会自动刷新 - 与
@StateObject和 @ObservedObject 配合使用
- 在视图中,@StateObject用于初始化ViewModel,@ObservedObject用于在子视图中共享ViewModel的实例
五、具体实践
接下来我们基于节程六对代码进行改造
1. 定义导航目标枚举
为了使用 NavigationPath 来管理页面堆栈,我们首先定义一个 NavigationDestination 枚举,表示可能的跳转目标
/// 定义导航目标,提供页面跳转的数据
/// 使用 `Hashable` 协议使其能够被 NavigationPath 识别
enum NavigationDestination: Hashable {
case page1
case pa

&spm=1001.2101.3001.5002&articleId=144860964&d=1&t=3&u=c57ee936ae7f4c9cb08b3f5cb5e4cd4b)
879

被折叠的 条评论
为什么被折叠?



