RxSwift 共享订阅执行顺序
RxSwift Shared Subscription Execution Order
如何确保 Observable
的订阅者将在另一个订阅者之后收到 onNext
事件?
我的例子如下:
let firstNameObservable = firstName.asObservable().shareReplay(1)
let lastNameObservable = lastName.asObservable().shareReplay(1)
let bioObservable = bio.asObservable().shareReplay(1)
let websiteObservable = website.asObservable().shareReplay(1)
firstNameObservable.subscribe(onNext: { [unowned self] firstName in self.accountDetails.firstName = firstName }).disposed(by: disposeBag)
lastNameObservable.subscribe(onNext: { [unowned self] lastName in self.accountDetails.lastName = lastName }).disposed(by: disposeBag)
bioObservable.subscribe(onNext: { [unowned self] bio in self.accountDetails.bio = bio }).disposed(by: disposeBag)
websiteObservable.subscribe(onNext: { [unowned self] website in self.accountDetails.website = website }).disposed(by: disposeBag)
Observable.combineLatest(firstNameObservable, lastNameObservable, bioObservable, websiteObservable)
{ [unowned self] _, _, _, _ in return self.accountDetails.validForSignUp }
.bind(to: isValid)
.disposed(by: disposeBag)
我希望最后一个 combineLatest
绑定在上面的 4 个 subscriptions
中的任何一个已经执行后触发。这是因为只有在 accountDetails
上设置了属性后,validForSignUp
才会准确。
我知道这个问题的解决方案是将 validForSignUp
变成 Variable
并观察它,但我们假设这是不可能的。
我会做更多这样的事情:
let accountDetails = AccountDetails(firstName: firstName.orEmpty.asObserable(), lastName: lastName.orEmpty.asObservable(), bio: bio.orEmpty.asObservable(), website: website.orEmpty.asObservable())
accountDetails.validForSignup
.bind(to: isValid)
.disposed(by: bag)
struct AccountDetails {
let validForSignup: Observable<Bool>
init(firstName: Observable<String>, lastName: Observable<String>, bio: Observable<String>, website: Observable<String>) {
let firstNameValid = firstName.map { [=10=].isValidFirstName }
let lastNameValid = lastName.map { [=10=].isValidLastName }
let bioValid = bio.map { [=10=].isValidBio }
let websiteValid = website.map { [=10=].isValidWebsite }
validForSignup = Observable.combineLatest([firstNameValid, lastNameValid, bioValid, websiteValid]) { [=10=].allTrue() }
}
}
extension String {
var isValidFirstName: Bool {
return !isEmpty // put approprate code here
}
var isValidLastName: Bool {
return !isEmpty // put approprate code here
}
var isValidBio: Bool {
return !isEmpty // put approprate code here
}
var isValidWebsite: Bool {
return !isEmpty // put approprate code here
}
}
extension Sequence where Iterator.Element == Bool {
func allTrue() -> Bool {
return !contains(false)
}
}
您可以通过一次订阅来处理您的数据验证。下面是如何完成的,我将把组合事件绑定到执行组合结果验证的 Observable。
let fields = [firstNameObservable,
lastNameObservable,
bioObservable,
websiteObservable]
let validFields = Observable.combineLatest(fields).bind(to: validateFields)
将提供组合结果验证的 Observable 可能类似于以下函数。
func validateFields<T>(allFields: Observable<[T]>) -> Observable<Bool>
{
return allFields.map { fieldData in
var result: Bool = false
/* Is the data valid? */
return result;
}
}
每次有来自任何字段 Observable 的新数据时,Observable validFields
都会更新验证结果。使用 combineLatest
,您可以获得额外的好处,即保持源 Observables 的顺序。这个解决方案是在不诉诸状态存储的情况下实现的,使其完全反应。
如何确保 Observable
的订阅者将在另一个订阅者之后收到 onNext
事件?
我的例子如下:
let firstNameObservable = firstName.asObservable().shareReplay(1)
let lastNameObservable = lastName.asObservable().shareReplay(1)
let bioObservable = bio.asObservable().shareReplay(1)
let websiteObservable = website.asObservable().shareReplay(1)
firstNameObservable.subscribe(onNext: { [unowned self] firstName in self.accountDetails.firstName = firstName }).disposed(by: disposeBag)
lastNameObservable.subscribe(onNext: { [unowned self] lastName in self.accountDetails.lastName = lastName }).disposed(by: disposeBag)
bioObservable.subscribe(onNext: { [unowned self] bio in self.accountDetails.bio = bio }).disposed(by: disposeBag)
websiteObservable.subscribe(onNext: { [unowned self] website in self.accountDetails.website = website }).disposed(by: disposeBag)
Observable.combineLatest(firstNameObservable, lastNameObservable, bioObservable, websiteObservable)
{ [unowned self] _, _, _, _ in return self.accountDetails.validForSignUp }
.bind(to: isValid)
.disposed(by: disposeBag)
我希望最后一个 combineLatest
绑定在上面的 4 个 subscriptions
中的任何一个已经执行后触发。这是因为只有在 accountDetails
上设置了属性后,validForSignUp
才会准确。
我知道这个问题的解决方案是将 validForSignUp
变成 Variable
并观察它,但我们假设这是不可能的。
我会做更多这样的事情:
let accountDetails = AccountDetails(firstName: firstName.orEmpty.asObserable(), lastName: lastName.orEmpty.asObservable(), bio: bio.orEmpty.asObservable(), website: website.orEmpty.asObservable())
accountDetails.validForSignup
.bind(to: isValid)
.disposed(by: bag)
struct AccountDetails {
let validForSignup: Observable<Bool>
init(firstName: Observable<String>, lastName: Observable<String>, bio: Observable<String>, website: Observable<String>) {
let firstNameValid = firstName.map { [=10=].isValidFirstName }
let lastNameValid = lastName.map { [=10=].isValidLastName }
let bioValid = bio.map { [=10=].isValidBio }
let websiteValid = website.map { [=10=].isValidWebsite }
validForSignup = Observable.combineLatest([firstNameValid, lastNameValid, bioValid, websiteValid]) { [=10=].allTrue() }
}
}
extension String {
var isValidFirstName: Bool {
return !isEmpty // put approprate code here
}
var isValidLastName: Bool {
return !isEmpty // put approprate code here
}
var isValidBio: Bool {
return !isEmpty // put approprate code here
}
var isValidWebsite: Bool {
return !isEmpty // put approprate code here
}
}
extension Sequence where Iterator.Element == Bool {
func allTrue() -> Bool {
return !contains(false)
}
}
您可以通过一次订阅来处理您的数据验证。下面是如何完成的,我将把组合事件绑定到执行组合结果验证的 Observable。
let fields = [firstNameObservable,
lastNameObservable,
bioObservable,
websiteObservable]
let validFields = Observable.combineLatest(fields).bind(to: validateFields)
将提供组合结果验证的 Observable 可能类似于以下函数。
func validateFields<T>(allFields: Observable<[T]>) -> Observable<Bool>
{
return allFields.map { fieldData in
var result: Bool = false
/* Is the data valid? */
return result;
}
}
每次有来自任何字段 Observable 的新数据时,Observable validFields
都会更新验证结果。使用 combineLatest
,您可以获得额外的好处,即保持源 Observables 的顺序。这个解决方案是在不诉诸状态存储的情况下实现的,使其完全反应。