2017-05-06 38 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这是一个视图模型,处理从服务器按需下载页面下载数据。它包含一个完整的测试套件。如果您对此有任何疑问,您可以在此发布或作为对要点的评论。是的,它包含一个变量,有时它们是不可避免的。 –