【问题标题】:RxSwift Variable composition without subscribe/bind/drive没有订阅/绑定/驱动的 RxSwift 变量组合
【发布时间】:2017-05-06 16:34:24
【问题描述】:

我需要 viewModel 中的一些内部状态,但也尝试遵循“无订阅/绑定/驱动/...”的理想方法,并且仅在 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
                })
        })
} 

【问题讨论】:

  • 如果没有订阅或绑定,那么什么都不会发生。 Observables 是惰性的,除非被观察,否则不会做任何工作。
  • @DanielT。同意,但实现“最大关注点分离”的重点是从视图控制器中的调用链接订阅。 问题是我不知道如何在订阅链中包含Variable 例如,如果在我的 VC 中我订阅了我的 viewModel 中的 (A),那么因为这个 (A) 是绑定的到其定义中的另一个可观察对象,如上面的fetchUserProfiles() 函数,它将链接订阅userProfilesToFetch 等等。我想不通的是如何通过指定它应该观察什么来链接变量本身。

标签: ios swift rx-swift reactivex


【解决方案1】:

“理想方法”是避免使用主题/变量。相反,更喜欢序列发射器(返回 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)
}

【讨论】:

  • 没错,我一直在努力避免使用任何类型的Subject,但由于某种原因,我感觉我的复杂用例“需要状态”。我想这完全是我自己的限制,我放弃了在没有它们的情况下找到正确的方法,更重要的是因为我找不到可以学习的“复杂”RxSwift 应用程序。您的回复给了我新的想法,我会尝试重新思考问题。谢谢!
  • 这里有一个复杂的例子:gist.github.com/dtartaglia/10bc5eb821c752ad45f281c6f4e3034b 它是一个视图模型,用于处理按需页面中从服务器下载数据。它包括一个完整的测试套件。如果您对此有任何疑问,可以在此处发布 SO 或作为对要点的评论。是的,它包含一个变量,有时它们是不可避免的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-09
  • 1970-01-01
相关资源
最近更新 更多