尝试编译以下代码时:
class LoginViewModel: ObservableObject, Identifiable {
@Published var mailAdress: String = ""
@Published var password: String = ""
@Published var showRegister = false
@Published var showPasswordReset = false
private let applicationStore: ApplicationStore
init(applicationStore: ApplicationStore) {
self.applicationStore = applicationStore
}
var passwordResetView: some View {
PasswordResetView(isPresented: $showPasswordReset) // This is where the error happens
}
}
PasswordResetView如下所示:
struct PasswordResetView: View {
@Binding var isPresented: Bool
@State var mailAddress: String = ""
var body: some View {
EmptyView()
}
}
}
我收到错误编译错误
Cannot convert value of type 'Published<Bool>.Publisher' to expected argument type 'Binding<Bool>'
如果我从LoginViewModel类外部使用已发布的变量,它将运行正常:
struct LoginView: View {
@ObservedObject var viewModel: LoginViewModel
init(viewModel: LoginViewModel) {
self.viewModel = viewModel
}
var body: some View {
PasswordResetView(isPresented: self.$viewModel.showPasswordReset)
}
}
有人建议我在这里做错了吗?我有机会可以从拥有的类内部将已发布的变量作为绑定传递吗?
谢谢!
答案 0 :(得分:1)
** Combine&SwiftUI仍然是新手,因此不确定是否有更好的方法来处理**
您可以初始化发布者的绑定。
https://developer.apple.com/documentation/swiftui/binding/init(get:set:)-6g3d5
let binding = Binding(
get: { [weak self] in
(self?.showPasswordReset ?? false)
},
set: { [weak self] in
self?.showPasswordReset = $0
}
)
PasswordResetView(isPresented: binding)
答案 1 :(得分:1)
这是可行的方法-在生成的视图中进行观察并避免工厂与演示者之间紧密耦合的想法。
在Xcode 12 / iOS 14上进行了测试(对于较旧的系统,可能需要进行一些调整)
protocol ResetViewModel {
var showPasswordReset: Bool { get set }
}
struct PasswordResetView<Model: ResetViewModel & ObservableObject>: View {
@ObservedObject var resetModel: Model
var body: some View {
if resetModel.showPasswordReset {
Text("Show password reset")
} else {
Text("Show something else")
}
}
}
class LoginViewModel: ObservableObject, Identifiable, ResetViewModel {
@Published var mailAdress: String = ""
@Published var password: String = ""
@Published var showRegister = false
@Published var showPasswordReset = false
private let applicationStore: ApplicationStore
init(applicationStore: ApplicationStore) {
self.applicationStore = applicationStore
}
var passwordResetView: some View {
PasswordResetView(resetModel: self)
}
}
答案 2 :(得分:0)
对于指出以下错误的错误:“无法将'Binding'类型的值转换为预期的参数类型'Bool'”解决方案是使用下图所示的wrappedValue。
如果您具有具有isEnabled属性的MyObject对象,并且需要将其用作普通Bool类型而不是“ Binding”,请执行此操作 myView.disabled($ myObject.isEnabled.wrappedValue)
答案 3 :(得分:0)
我认为这里要理解的重要一点是“$”在组合上下文中的作用。
“$”的作用是将变量“showPasswordReset”的变化发布到它被观察到的地方。
当它位于类型之前时,它不代表您为变量声明的类型(在这种情况下为布尔值),它代表一个发布者,如果您想要该类型的值,只需删除“$”即可。< /p>
"$" 用于变量被标记为@ObservedObject 的上下文中, (这里的 ObservableObject 是 LoginViewModel,你订阅它以监听它作为发布者的变量市场的变化)
const { loading as userLoading, error as userError, data as userData} = user;
const { loading as customerLoading, error as customerError, data as customerData} = customer;
在该上下文中(例如 ContentView),“showPasswordReset”的更改将在其值更新时“发布”,以便使用新值更新视图。