2017-05-06 51 views
1

我需要viewModel中的一些內部狀態,但也試圖遵循「無訂閱/綁定/驅動器/ ...」的理想方法,只能在Observables之間編寫。RxSwift無訂閱/綁定/驅動器的變量組合

如何指定Variable觀察的內容?

實施例:

private var userProfilesToFetch = Variable<[String]>([]) 
private var users: Variable<[User]> { 

    return //something that observes fetchUserProfiles() and when it emits, appends to its .value 
} 

private func fetchUserProfiles() -> Observable<User?> { 

    let reference = databaseRef.child("users") 

    return userProfilesToFetch.asObservable() 
     .filter({ $0 != [] }) 
     .map({ $0.last! }) 
     .flatMap({ (userId) -> Observable<User?> in 

      return self.service.observeAllChildren(of: reference.child(userId), by: .value) 
       .map({ (snapshot) -> User? in 

         guard let values = snapshot.value as? [String: AnyObject] else { return nil } 

         var user = User(dictionary: values) 

         user.id = snapshot.key 

         return user 
       }) 
     }) 
} 
+0

如果沒有訂閱或綁定,則不會發生任何事情。觀察對象是懶惰的,除非被觀察到,否則不會做任何工作。 –

+0

@DanielT。同意,但實現「最大關注點分離」的關鍵在於在視圖控制器中通過調用鏈接訂閱。 **事情是我無法弄清楚如何在訂閱鏈中包含'Variable' **例如,如果在我的VC中我訂閱了(A)在我的viewModel中,那麼因爲這個(A)綁定到另一個observable在其定義中,就像上面的'fetchUserProfiles()'函數一樣,它將鏈接訂閱到'userProfilesToFetch'等等。我無法弄清楚的是,如何通過指定應該遵守的內容來鏈接變量本身。 – Herakleis

回答

2

「理想的方法」 是要避免使用的受試者/變量。相反,有利於序列發射器(返回可觀察的函數),序列接收器(接受可觀察參數的函數)和序列變換器(兩者兼有的功能)。

序列發射器和接收器必須執行副作用並且內部的序列接收器中,必須有一個訂閱/綁定才能解壓值並使用它。

發射器和接收器之間應該有直接明顯的聯繫。主題/變量傾向於打破該鏈接。

在這種理想的方法中,您的「視圖模型」不是包含一堆變量的類/結構。您的視圖模型是一個函數,它將observables作爲參數並返回視圖控制器綁定的可觀察值。例如:

class MyViewController: UIViewController { 
    @IBOutlet weak var name: UITextView! 
    @IBOutlet weak var label: UILabel! 

    override 
    func viewDidLoad() { 
     super.viewDidLoad() 
     let viewModel = myViewModel(name: name.rx.text.orEmpty) 
     viewModel.label.bind(to: label.rx.text).disposed(by: bag) 
    } 
    let bag = DisposeBag() 
} 

struct MyViewModel { 
    let label: Observable<String> 
} 

// this function could be turned into an `init` method on the MyViewModel struct if you would prefer. 
fun myViewModel(name: Observable<String>) -> MyViewModel { 
    let label = name.map { "Hello \($0)!" } 
    return MyViewModel(label: label) 
} 
+0

的確,我一直試圖避免使用任何類型的「Subject」,但出於某種原因,我感覺我的複雜用例「需要狀態」。我想這是我自己的限制,我放棄了找出沒有它們的正確方法,更重要的是因爲我找不到可以學習的「複雜」RxSwift應用程序。您的回覆給了我新的想法,我會嘗試重新考慮問題。謝謝! – Herakleis

+0

下面是一個複雜的例子:https://gist.github.com/dtartaglia/10bc5eb821c752ad45f281c6f4e3034b這是一個視圖模型,處理從服務器按需下載頁面下載數據。它包含一個完整的測試套件。如果您對此有任何疑問,您可以在此發佈或作爲對要點的評論。是的,它包含一個變量,有時它們是不可避免的。 –