2017-05-26 179 views
3

如何確保Observable的訂戶將接收另一訂戶後的onNext事件?RxSwift共享訂閱執行訂單

我的例子如下:

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並觀察它,但是讓我們假設是不可能的。

+0

isValid是變量嗎?如果可能的話,你應該避免使用變量和主題。 –

回答

2

我會做更多的事情是這樣的:

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) 
    } 
} 
+0

也許這個問題的解決方案實際上是一種不同的方法。感謝你的回答。 –

+0

是的,如果你正在編寫你的反應式代碼,以便這樣的順序重要,那麼你做錯了。 –

1

你可以用一個單一的訂閱處理你的數據驗證。以下是如何完成將組合事件綁定到執行組合結果驗證的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; 
    } 
} 

可觀察validFields將與驗證結果每次有任何現場觀測量的新數據時進行更新。使用combineLatest,您有額外的好處,即您的源Observable的順序得以維護。該解決方案無需藉助狀態存儲就可以完成反應。

+0

我的目標實際上是確保在AccountDetails屬性設置後執行驗證。雖然你的答案很有趣,但它並不一定給我解決我的具體問題。 –