简体   繁体   English

如何模拟可访问RxSwift中最新值的计算属性?

[英]How do I emulate a computed property with access to the latest value in RxSwift?

If I want to emulate a standard property of eg a Bool in RxSwift I can use let isValid = Variable<Bool>(false) and then use .value to get the last value inline and .asObservable() to access the stream. 如果要在RxSwift中模拟Bool标准属性,则可以使用let isValid = Variable<Bool>(false) ,然后使用.value内联获取最后一个值,并使用.asObservable()访问流。

However I want to emulate a computed propery eg var isValid { return self.password.characters.count > 0 } and also be able to get the last value inline as well as in the form of an observable stream. 但是我想模拟一个计算的属性,例如var isValid { return self.password.characters.count > 0 }并且还能够内联以及以可观察流的形式获取最后一个值。

I want to be able to do both so I can write code like ... 我希望能够做到这两者,所以我可以编写类似...的代码

if isValid.value { // isValid is Variable<Bool>
    // ... do something ....
}

as well as bind to eg a TextField 以及绑定到例如TextField

I know I can write as a pure Observable as follows ... 我知道我可以写成如下所示的纯Observable ...

var isValid: Observable<Bool> {
    return self.username.asObservable().map { username in   // username is Variable<String>
        return username.characters.count > 0
    }
}

but then I have to refactor the previous example to be .... 但是然后我必须将前面的示例重构为....

isValid.subscribe { isValid in 
    if isValid.element {
        // ... do something ....
    }
}.dispose(of: self.disposeBag)

How then do I express a computed property in RxSwift which can be consumed as an inline value as well as a stream? 然后,我如何在RxSwift中表达一个计算属性,该属性可以作为内联值和流使用?

I had the same problem and ended up with a solution that does not look clean but works. 我遇到了同样的问题,最终得到的解决方案看起来不干净,但可以正常工作。 I would add a new var valid: Bool = false and a subscription to the isValid observable that updates it 我将添加一个新的var valid: Bool = false和对isValid observable的订阅以对其进行更新

isValid.subscribe(onNext:{ [weak self] value in self?.valid = valid}) isValid.subscribe(onNext:{self中的[weak self]值?.valid = valid})

With this isValid is used for binding and subscriptions and valid for use in imperative code. 使用此方法, isValid用于绑定和订阅,并且在命令式代码中valid

Btw your definition of isValid is kind of "unnatural", just make it a let isValid: Observable<Bool> and assign it in init like isValid = username.asObservable().map({$0.characters.count > 0}) 顺便说一句,您对isValid的定义有点“不自然”,只要让它成为let isValid: Observable<Bool>并像isValid = username.asObservable().map({$0.characters.count > 0})这样在init分配即可isValid = username.asObservable().map({$0.characters.count > 0})

Update: 更新:

Another solution is using RxBlockling, you can get the current value with try! isValid.toBlocking().single() 另一个解决方案是使用RxBlockling,您可以try! isValid.toBlocking().single()使用当前值try! isValid.toBlocking().single() try! isValid.toBlocking().single() but I think it is a worse solution and generally not recommended. try! isValid.toBlocking().single()但我认为这是一个较差的解决方案,通常不建议这样做。

Try this: 尝试这个:

let username = Variable("")

private let _isValid: Observable<Bool> = username.asObservable().map{ $0.characters.count > 0 }

let isValid = Variable(false)

Then, in your init , viewDidLoad or wherever: 然后,在您的initviewDidLoad或任何地方:

_isValid.asObservable()
    .bind(to: isValid)
    .disposed(by: bag)

You can test it with: 您可以使用以下方法进行测试:

isValid.asObservable()
    .subscribe(onNext: {
        print("value: \($0)")

    })
    .disposed(by: disposeBag)

username.value = "xfreire"

// OUTPUTS:
// value: false
// value: true

and you are still able to do: 而且您仍然可以执行以下操作:

if isValid.value {
    // ...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM