如何使用`.fullScreenCover(isPresented: $viewModel.loginSuccessful)` 以非布尔值。

huangapple go评论74阅读模式
英文:

How to use .fullScreenCover(isPresented: $viewModel.loginSuccessful) with a non bool value

问题

我有一个视图,使用以下视图修改器:

.fullScreenCover(isPresented: $viewModel.user) {

这会生成一个错误:

无法将类型为 'Binding<User?>' 的值转换为期望的参数类型 'Binding<Bool>'

当用户点击登录按钮时,它将触发一个在viewModel中的异步方法的调用,如果登录成功,它将设置其user属性,如果登录不成功,则设置其error属性。

ViewModel:

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

...
}

我知道我可以创建一些bool类型的@Published变量,但我想避免在两个地方确认用户已成功登录(使用User对象和一个bool值)。

英文:

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 &#39;Binding&lt;User?&gt;&#39; to expected argument type &#39;Binding&lt;Bool&gt;&#39;

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

答案1

得分: 2

使用fullScreenCover(item:onDismiss:content:) 方法应该能满足你的需求。

一般我会建议创建一个像这样的enum

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

@Published var userState: UserState

好处在于这会防止你陷入usererror同时存在的糟糕状态。

添加一个计算布尔变量,用来返回userState是否当前为.user,这样你就可以在初始化fullScreenCover时使用当前的方法,而不需要引入第二个真值。

另外,你还可以使用类似PointFree的SwiftUI导航工具,直接使用枚举值来呈现视图:

.fullscreenCover(
  unwrapping: $viewModel.userState,
  case: /UserState.user
) { $user in 
  // 视图
}
英文:

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
}

答案2

得分: 0

你可以像这样给 Binding 添加一个扩展...

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

然后你可以将你的 Binding<Optional<T>> 转换为 Binding<Bool>

你可以像这样使用它...

.fullScreenCover(isPresented: $viewModel.user.isPresent()) {
英文:

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

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

And then you can turn your Binding&lt;Optional&lt;T&gt;&gt; into a Binding&lt;Bool&gt;

You can use it like...

.fullScreenCover(isPresented: $viewModel.user.isPresent()) {

huangapple
  • 本文由 发表于 2023年3月10日 00:32:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/75687475.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定