SwiftUI中使用Environment共享@Observable ViewModel时,$loginVM作用域不存在的报错问题
SwiftUI中使用Environment共享@Observable ViewModel时,$loginVM作用域不存在的报错问题
嘿,你已经离解决问题只差一步啦!这个报错其实是SwiftUI里一个很常见的小坑——当你通过@Environment获取@Observable类型的ViewModel时,不能直接用$前缀来访问它的绑定属性。$前缀是@State、@StateObject或者@Bindable这些属性包装器专属的,而你从环境里拿到的loginVM只是一个普通的Observable实例,没有自带生成绑定的$前缀能力。
我给你两种简单的解决方法,选哪个都能搞定:
方法一:在视图里给loginVM添加@Bindable包装
直接在LoginView里,把从环境拿到的loginVM包装成@Bindable属性,这样就能像以前一样用$前缀访问绑定了:
import SwiftUI struct LoginView: View { @Environment(LoginViewModel.self) private var loginVM // 把环境中的ViewModel包装成可绑定的实例 @Bindable private var bindableLoginVM = loginVM var body: some View { VStack(alignment: .leading) { Text("My Test View") } .alert("Message Title", isPresented: $bindableLoginVM.showApiAlert) { Button("OK") { // 这里写OK按钮的处理逻辑 } } message: { Text("The message text") } } }
方法二:在使用绑定时临时包装成Bindable
如果你不想额外声明一个属性,也可以直接在.alert的参数里临时把loginVM包装成Bindable,代码会更简洁:
import SwiftUI struct LoginView: View { @Environment(LoginViewModel.self) private var loginVM var body: some View { VStack(alignment: .leading) { Text("My Test View") } .alert("Message Title", isPresented: Bindable(loginVM).$showApiAlert) { Button("OK") { // 这里写OK按钮的处理逻辑 } } message: { Text("The message text") } } }
为什么之前用@State的时候没问题?
之前你在视图里用@State声明loginVM时,@State本身是属性包装器,它会自动给你生成带$前缀的绑定,所以直接用$loginVM.showApiAlert是有效的。但换成环境共享后,你拿到的是ViewModel的原始实例,没有这个自动生成绑定的能力,所以必须手动用Bindable包装一下。
另外要确认你的App结构是完全没问题的,你现在的MyApp代码写法是正确的:
@main struct MyApp: App { @Bindable private var loginVM = LoginViewModel() var body: some Scene { WindowGroup { ContentView() .environment(loginVM) } } }
这样改完之后,Xcode的报错应该就消失了,而且你也能在多个视图里共享同一个LoginViewModel实例啦!
内容来源于stack exchange
相关产品推荐
相关产品推荐

