0

I've got a view that uses the following view modifier:

        .fullScreenCover(isPresented: $viewModel.user) {

This will generate a error:

Cannot convert value of type 'Binding<User?>' to expected argument type 'Binding<Bool>'

When the user taps the login button, it will trigger a call to an async method in the viewModel that will set its user property if the login was successful or set its error property if not.

ViewModel:

class LoginViewModel: ObservableObject {
    
    @Published var user:User?
    @Published var error:Error?

...
}

I know I can create a couple of bool published vars, but I would like to avoid having to places where I acknowledge a user has logged successfully ( with the User object and a bool )

Thanks

xarly
  • 2,054
  • 4
  • 24
  • 40

2 Answers2

2

Using the fullScreenCover(item:onDismiss:content:) method should do what you want it to.

Generally I would recommend making an enum like this though:

enum UserState {
    case user(User)
    case error(Error)
}

@Published var userState: UserState

The benefit is that this will prevent you from getting into a bad state where both user and error are present.

Adding a computed boolean variable that returns whether userState is currently .user would allow you to use your current fullScreenCover initialization without adding a second source of truth.

As a side note, you could also use a tool like PointFree's SwiftUI Navigation to use the enum value directly for presenting the sheet:

.fullscreenCover(
  unwrapping: $viewModel.userState,
  case: /UserState.user
) { $user in 
  // View
}
mimo
  • 247
  • 1
  • 7
  • for the recommendation of using PointFree's navigation tools. – Fogmeister Mar 09 '23 at 17:03
  • I love their approach to creating Swift tools, they've come up with some really great stuff! – mimo Mar 09 '23 at 17:11
  • Wow nice advise, much prefer it. Thanks @mimo. Just one question, if I add the computed boolean variable and I use it in the `fullScreenCover(isPresented:` method I will get a error: `Cannot assign to property: 'isUserLoggedIn' is a get-only property` – xarly Mar 09 '23 at 18:50
0

You can add an extension to Binding like this...

extension Binding {
  public func isPresent<Wrapped>() -> Binding<Bool> where Value == Wrapped? {
    .init(
      get: { self.wrappedValue != nil },
      set: { isPresent in
        if !isPresent {
          wrappedValue = nil
        }
      }
    )
  }
}

And then you can turn your Binding<Optional<T>> into a Binding<Bool>

You can use it like...

.fullScreenCover(isPresented: $viewModel.user.isPresent()) {
Fogmeister
  • 76,236
  • 42
  • 207
  • 306