swift - 触发 CombineLatest 在 Combine 中传播初始值

标签 swift reactive-programming combinelatest combine

我有两个字符串发布者和一个返回 AnyPublisher 的计算属性。逻辑很简单,但我想知道是否有任何方法可以传播初始值。我认为这应该是有可能的,因为发布者有初始值。

在 VC 中,我从 ViewModel(从 textField)为 Publishers 分配新值。

firstTextField.addTarget(self, action: #selector(firstTextFieldDidChange(_:)), for: .editingChanged)
secondTextField.addTarget(self, action: #selector(secondTextFieldDidChange(_:)), for: .editingChanged)

@objc private func firstTextFieldDidChange(_ textField: UITextField) {
 viewModel.firstPublisher = textField.text ?? ""
}
@objc private func secondTextFieldDidChange(_ textField: UITextField) {
 viewModel.secondPublisher = textField.text ?? ""
}

然后我将 Publisher (combineLatest) 分配给我的按钮:

_ = viewModel.validatedText
   .receive(on: RunLoop.main)
   .assign(to: \.isEnabled, on: button)

在 VM 中我有两个发布者:

@Published var firstPublisher: String = ""
@Published var secondPublisher: String = ""

和 CombineLatest:

var validatedText: AnyPublisher<Bool, Never> {
    return Publishers.CombineLatest($firstPublisher, $secondPublisher) {
        return !($0.isEmpty || $1.isEmpty)
        }.eraseToAnyPublisher()
}

validatedText 只有在我开始在两个文本字段中输入时才开始发布新值。例如,我尝试在 VM 的 init 中分配一些新值(给第一和第二发布者),但它也没有用。有什么办法可以做到这一点,或者我必须在不使用组合的情况下设置按钮的初始状态(禁用它)?

最佳答案

不幸的是,这似乎只是 @Published 的行为,但您可以通过在生成的 Publisher 中添加一个初始值来解决此问题:

var validatedText: AnyPublisher<Bool, Never> {
    let validate: (String, String) -> Bool = {
        !($0.isEmpty || $1.isEmpty)
    }
    return Publishers.CombineLatest($firstPublisher, $secondPublisher, transform: validate)
        .prepend(validate(firstPublisher, secondPublisher))
        .eraseToAnyPublisher()
}

相反,如果您更愿意采用这种方法,那么编写您自己的属性委托(delegate)以获得您想要的行为是相当简单的:

import Combine

@propertyDelegate
struct InitialPublished<Value> : Publisher {
    typealias Output = Value
    typealias Failure = Never

    private let subject: CurrentValueSubject<Output, Failure>

    var value: Value {
        set { subject.value = newValue }
        get { subject.value }
    }

    init(initialValue: Value) {
        subject = CurrentValueSubject(initialValue)
    }

    func receive<S>(subscriber: S) where S: Subscriber, Value == S.Input, Failure == S.Failure {
        subject.receive(subscriber: subscriber)
    }
}

关于swift - 触发 CombineLatest 在 Combine 中传播初始值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56823604/

相关文章:

swift - @AppStorage 不更新 View

java - 如何将 rxJava2 的 Observable 转换为 Completable?

java - RxJava-我的运算符(operator)上缺少Back压异常?

swift - 你应该如何处理 UIAlertAction 的闭包参数

ios - 以编程方式将 UIScrollView 滚动到 Swift 中子 UIView( subview )的顶部

android - 在 RxJava 中的 TimeoutException 上恢复 Flowable

RxJS combineAll 运算符,解释

angular - RXJS- Angular : Two Observable<booleans> should return Observable<boolean>

javascript - 结合 Rxjs 5 中的最新行为?

ios - 将数据从 ViewController 传递到 ChildContainerContainer Swift