英文:
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 '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
答案1
得分: 2
使用fullScreenCover(item:onDismiss:content:)
方法应该能满足你的需求。
一般我会建议创建一个像这样的enum
:
enum UserState {
case user(User)
case error(Error)
}
@Published var userState: UserState
好处在于这会防止你陷入user
和error
同时存在的糟糕状态。
添加一个计算布尔变量,用来返回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<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()) {
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论