Cannot convert value of type 'Published<Bool>.Publisher' to expected argument type 'Binding<Bool>'
Solution 1
Here is possible approach - the idea to make possible observation in generated view and avoid tight coupling between factory & presenter.
Tested with Xcode 12 / iOS 14 (for older systems some tuning might be needed)
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)
}
}
Solution 2
** Still new to Combine & SwiftUI so not sure if there is better way to approach **
You can initalize Binding from publisher.
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)
Solution 3
I think the important thing to understand here is what "$" does in the Combine context.
What "$" does is to publish the changes of the variable "showPasswordReset" where it is being observed.
when it precedes a type, it doesn't represent the type you declared for the variable (Boolean in this case), it represents a publisher, if you want the value of the type, just remove the "$".
"$" is used in the context where a variable was marked as an @ObservedObject, (the ObservableObject here is LoginViewModel and you subscribe to it to listen for changes in its variables market as publishers)
struct ContentView: View {
@ObservedObject var loginViewModel: LoginViewModel...
in that context (the ContentView for example) the changes of "showPasswordReset" are going to be 'Published' when its value is updated so the view is updated with the new value.
Jan Koch
Updated on June 06, 2022Comments
-
Jan Koch almost 2 years
When trying to compile the following code:
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 } }
Where PasswordResetView looks like this:
struct PasswordResetView: View { @Binding var isPresented: Bool @State var mailAddress: String = "" var body: some View { EmptyView() } } }
I get the error compile error
Cannot convert value of type 'Published<Bool>.Publisher' to expected argument type 'Binding<Bool>'
If I use the published variable from outside the LoginViewModel class it just works fine:
struct LoginView: View { @ObservedObject var viewModel: LoginViewModel init(viewModel: LoginViewModel) { self.viewModel = viewModel } var body: some View { PasswordResetView(isPresented: self.$viewModel.showPasswordReset) } }
Any suggestions what I am doing wrong here? Any chance I can pass a published variable as a binding from inside the owning class?
Thanks!
-
Jan Koch almost 4 yearsThanks. I saw that as well but it looks a bit clunky. But I will try it out now :-)
-
B Porr about 3 yearsThat's a very smart idea by just putting the ObservedObject in the view and with that preventing any type issues. I use it to update a progress bar which is monitoring a published progress value in another thread and works perfectly.
-
Ahmadreza about 3 yearsI get Cannot find 'self' in scope
-
obevan about 2 yearsThis should be the accepted answer!
-
Jayson about 2 yearsThat makes so much sense I don't know why I didn't think about it. lol
-
Hajji Daoud about 2 yearsCan't believe this actually worked
-
Parth Mehrotra about 2 yearsMost people probably have
globalSettings.$tutorialView
because that's what XCode suggests while you're typing.