RxSwift Shared Subscription Execution Order

ぐ巨炮叔叔 提交于 2020-01-14 10:45:33

问题


How can I ensure that a subscriber to an Observable will receive the onNext event after another subscriber?

My example is the following:

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)

I would like for that last combineLatest binding to trigger after any of the 4 subscriptions above it have already executed. This is because it is only after the properties on accountDetails have been set that the validForSignUp will be accurate.

I am aware that a solution to this problem would be to make validForSignUp a Variable and observe it, but let's assume that is not possible.


回答1:


I would do something more like this:

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 { $0.isValidFirstName }
        let lastNameValid = lastName.map { $0.isValidLastName }
        let bioValid = bio.map { $0.isValidBio }
        let websiteValid = website.map { $0.isValidWebsite }

        validForSignup = Observable.combineLatest([firstNameValid, lastNameValid, bioValid, websiteValid]) { $0.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)
    }
}



回答2:


You can handle your data validation with a single subscribe. Here's how it can be done where I'll bind the combined events to an Observable that performs validation of the combined results.

let fields = [firstNameObservable, 
              lastNameObservable, 
              bioObservable, 
              websiteObservable]
let validFields = Observable.combineLatest(fields).bind(to: validateFields)

The Observable that will deliver the validation of the combined results could look something like the following function.

func validateFields<T>(allFields: Observable<[T]>) -> Observable<Bool>
{
    return allFields.map { fieldData in
        var result: Bool = false

        /* Is the data valid? */

        return result;
    }
}

The Observable validFields will be updated with a validation result every time there is new data from any of the field Observables. With combineLatest, you have the added benefit that the order of your source Observables is maintained. This solution is accomplished without resorting to storage of state making it completely reactive.



来源:https://stackoverflow.com/questions/44204583/rxswift-shared-subscription-execution-order

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!