RxSwift没有subscribe / bind / drive的变量组合

时间:2017-05-06 16:34:25

标签: ios swift rx-swift reactivex

我在viewModel中需要一些内部状态,但也尝试遵循“no subscription / bind / drive / ...”理想方法,并且仅在Observables之间进行组合。

如何指定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
                })
        })
} 

1 个答案:

答案 0 :(得分:2)

&#34;理想的方法&#34;是避免使用Subjects / Variables。相反,支持序列发射器(返回可观察的函数)序列接收器(接受可观察的参数的函数)和序列变换器(同时执行这两者的函数)。

序列发射器和接收器必然会执行副作用,而序列接收器中,必须有一个订阅/绑定才能解压并使用它。

发射器和接收器之间应该存在直接且明显的联系。主题/变量往往打破这种联系。

在这种理想的方法中,您的视图模型&#34;不是包含一堆变量的类/结构。您的视图模型是一个函数,它将observable作为参数并返回视图控制器要绑定的observable。例如:

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