skip to Main Content

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

2

Answers


  1. 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
    }
    
    Login or Signup to reply.
  2. 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()) {
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search