import SwiftUI
class DoTryCatchThrowsDemoDataManager {
private var isError: Bool = false
func fetchTitle(_ completion: (String?, Error?) -> Void) {
if !isError {
completion("New title", nil)
} else {
completion(nil, URLError(.badURL))
}
}
}
class DoTryCatchThrowsDemoViewModel: ObservableObject {
@Published var title: String = "Original title"
private var dataManager = DoTryCatchThrowsDemoDataManager()
func getTitle() {
dataManager.fetchTitle { [weak self] title, error in
guard let self else { return }
if let title {
self.title = title
} else if let error {
self.title = error.localizedDescription
}
}
}
}
struct DoTryCatchThrowsDemo: View {
@StateObject private var viewModel = DoTryCatchThrowsDemoViewModel()
var body: some View {
Text(viewModel.title)
.font(.largeTitle)
.frame(width: 300, height: 300)
.background(Color.cyan)
.onTapGesture {
viewModel.getTitle()
}
}
}
@StateObject 是 SwiftUI 中的一个属性包装器(Property Wrapper),在管理视图的状态和依赖对象时起着重要作用,以下从基本概念、使用场景、使用方法、与其他属性包装器对比等方面详细介绍:
基本概念
在 SwiftUI 里,视图是值类型,每次视图重新渲染时,其状态可能会丢失或被重置。而 @StateObject 用于创建和管理引用类型(通常是遵循 ObservableObject 协议的类)的实例,并且保证该实例在视图的生命周期内是唯一且持久的,即无论视图如何刷新,@StateObject 包装的对象都会保持其状态。
使用场景
- 复杂状态管理:当视图需要管理复杂的状态逻辑,如网络请求、数据处理等,将这些逻辑封装在一个遵循
ObservableObject协议的类中,然后使用@StateObject来管理这个类的实例,能让视图代码更简洁,逻辑更清晰。 - 多视图共享状态:在多个视图之间共享同一个状态对象时,使用
@StateObject可以确保状态的一致性和持久性。
使用方法
1. 创建遵循 ObservableObject 协议的类
swift
import Combine
class MyViewModel: ObservableObject {
@Published var count = 0
func increment() {
count += 1
}
}
在上述代码中,MyViewModel 类遵循 ObservableObject 协议,使用 @Published 属性包装器标记的 count 属性,当该属性的值发生变化时,会自动发布通知,让依赖该对象的视图进行更新。increment 方法用于增加 count 的值。
2. 在视图中使用 @StateObject
swift
import SwiftUI
struct ContentView: View {
@StateObject private var viewModel = MyViewModel()
var body: some View {
VStack {
Text("Count: (viewModel.count)")
Button("Increment") {
viewModel.increment()
}
}
}
}
在 ContentView 中,使用 @StateObject 声明了一个 viewModel 实例。无论 ContentView 如何刷新,viewModel 始终是同一个实例,其状态会一直保留。点击按钮调用 viewModel 的 increment 方法,count 属性的值会增加,同时视图会自动更新显示新的 count 值。
与其他属性包装器对比
1. @StateObject 与 @ObservedObject
@StateObject用于创建和拥有一个ObservableObject实例,通常在视图第一次创建时初始化该实例,并且在视图的整个生命周期内保持不变。@ObservedObject用于观察一个已经存在的ObservableObject实例,它不会创建实例,只是对传入的实例进行观察。一般在子视图中使用@ObservedObject来观察父视图传递过来的状态对象。
示例:
swift
// 父视图使用 @StateObject 创建和管理 ViewModel
struct ParentView: View {
@StateObject private var viewModel = MyViewModel()
var body: some View {
ChildView(viewModel: viewModel)
}
}
// 子视图使用 @ObservedObject 观察传入的 ViewModel
struct ChildView: View {
@ObservedObject var viewModel: MyViewModel
var body: some View {
Text("Count in ChildView: (viewModel.count)")
}
}
2. @StateObject 与 @State
@State用于管理视图内部的简单值类型(如Int、String等)的状态,它主要用于处理视图自身的基本状态变化。@StateObject用于管理复杂的引用类型(遵循ObservableObject协议的类)的状态,适合处理更复杂的业务逻辑和数据管理。
注意事项
@StateObject修饰的对象必须在视图初始化时创建,否则可能会导致状态丢失或不一致。- 在 SwiftUI 中,尽量避免在
@StateObject对象的初始化过程中进行耗时操作,以免影响视图的加载性能。可以将耗时操作放在对象的方法中,在合适的时机调用