从现有的SwiftUI @States派生绑定

fre*_*bie 7 swift swiftui combine

我一直在玩SwiftUI和Combine,感觉好像有一种方法可以在视图中保留现有的@State属性并创建一个新属性。

例如,我有一个密码创建视图,其中包含用户的密码和passwordConfirm字段。我想采用这两个@State属性并派生一个新的@State,我可以在我的视图中使用它来断言输入是否有效。因此,为了简单起见:不等于空值。

苹果公司的文档说,有一个发行人正在装订,尽管我似乎看不到它。

这是一些无效的伪代码:

import SwiftUI
import Combine

struct CreatePasswordView : View {
    @State var password = ""
    @State var confirmation = ""
    lazy var valid = {
        return self.$password.publisher()
            .combineLatest(self.$confirmation)
            .map { $0 != "" && $0 == $1 }
    }

    var body: some View {
        SecureField($password, placeholder: Text("password"))

        SecureField($confirmation, placeholder: Text("confirm password"))

        NavigationButton(destination: NextView()) { Text("Done") }
            .disabled(!valid)
    }
}
Run Code Online (Sandbox Code Playgroud)

发现任何人。/如果可能的话,采取适当的方法?

更新Beta 2:

从beta 2版本开始可用,因此该代码的前半部分现在可以使用。在View中使用结果发布者的后半部分,我仍然没有弄清楚(disabled(!valid))。

import SwiftUI
import Combine

struct CreatePasswordView : View {
    @State var password = ""
    @State var confirmation = ""

    lazy var valid = {
        Publishers.CombineLatest(
            password.publisher(),
            confirmation.publisher(),
            transform: { String($0) != "" && $0 == $1 }
        )
    }()

    var body: some View {
        SecureField($password, placeholder: Text("password"))

        SecureField($confirmation, placeholder: Text("confirm password"))

        NavigationButton(destination: NextView()) { Text("Done") }
            .disabled(!valid)
    }
}
Run Code Online (Sandbox Code Playgroud)

谢谢。

Mat*_*ini 1

我目前不会按测试版的@State/@Published样子进行操作,但这里有一个简单的解决方法,可以满足您想要实现的目标。Combine

我将实现一个视图模型来保存密码、密码确认以及它是否有效

class ViewModel: NSObject, BindableObject {

    var didChange = PassthroughSubject<Void, Never>()

    var password: String = "" {
        didSet {
            didChange.send(())
        }
    }

    var passwordConfirmation: String = "" {
        didSet {
            didChange.send(())
        }
    }

    var isPasswordValid: Bool {
        return password == passwordConfirmation && password != ""
    }

}
Run Code Online (Sandbox Code Playgroud)

这样,只要密码或确认发生更改,就会重新计算视图。

@ObjectBinding然后我会对视图模型进行创建。

struct CreatePasswordView : View {

    @ObjectBinding var viewModel: ViewModel

    var body: some View {
        NavigationView {
            VStack {
                SecureField($viewModel.password,
                            placeholder: Text("password"))
                SecureField($viewModel.passwordConfirmation,
                            placeholder: Text("confirm password"))
                NavigationButton(destination: EmptyView()) { Text("Done") }
                    .disabled(!viewModel.isPasswordValid)
            }
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

我必须将视图放入 a 中NavigationView,因为NavigationButton如果它不在其中之一中,则似乎无法启用自身。