在ViewModel中更新带有RxSwift的列表

时间:2018-06-20 05:27:21

标签: swift mvvm rx-swift

我有一个呈现“节点”列表的VM。每个节点都有一个isCompletedisRead属性。它们呈现在表格视图中,每个单元格都有用于切换这些属性的按钮。

在页面加载时,我从服务器获取列表。现在,我只想更新那些节点。在我的VM中,我尝试了20多种方法,涉及各种操作员,策略,方法等。但是每次尝试都始终存在相同的问题。

我知道这实际上只是在更新某些内容,或者是View-> ViewModel通信。尽管如此,我还是花了令人尴尬的时间花了很多时间来模拟这个模型。因此,我必须缺少RxSwift,MVVM的一些非常基本的方面以及如何为突变建模。

这是我最近的尝试。

  let updates = Observable<(NodeIdentifier, AttribUpdate)?>.merge([
        toggleMarkReadSubject.map { ($0, AttribUpdate.isRead) },
        toggleFavoriteSubject.map { ($0, AttribUpdate.isFavorited) }
        ]).startWith(nil)

    nodes = Observable.combineLatest(dataFromService, updates, resultSelector: { (nodes, update) in
        guard let update = update else { return nodes }

        switch update.1 {
        case .isFavorited:
            return nodes.withFavoritedToggled(atId: update.0)
        case .isRead:
            return nodes.withMarkReadToggled(atId: update.0)
        }
    }).debug("new nodes", trimOutput: false)

我有一些主题通过nodeIdentifier和update操作(将枚举与每种更新类型的大小写一起使用)将切换事件映射到元组

nodes是驱动表格视图的主要输出。我combineLatestnodesFromService(服务/ api中的原始节点)。

现在,我得到[Node]事件,其中切换属性如下所示:[false, true, true, true, true]。因此它总是从false -> true开始,因为combineLatest总是从nodesFromService获取初始节点数组。

这就是让我发疯的原因。无论我采用哪种方式对其进行切片,这都是周期性的依赖。我真正需要的是将updates(切换事件)与"final nodes"流(实际上记住更新的流)组合在一起。但是,如果我什至能够做到这一点,我就会遇到递归的情况。因为updates首先产生了"final nodes"流!我感到完全迷失了。非常感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

我可以在这里找到两个选择。


由于您不会在节点的当前状态不存储任何位置,因此可以将主题添加到ViewModel中。在这种情况下,您可以保存节点的先前状态。

let nodesSubject = BehaviorSubject(value: [Node]())

...

updateSubject.map { updates in
    guard let nodes = try? nodesSubject.value() else { return [] }

    // Filter

}.subscribe(nodesSubject) // Save updated nodes back to subject

// update nodes subject on on next (you can do this as side effect instead with do(onNext:))
dataFromService.subscribe(nodesSubject)

在这种情况下,您最终将在ViewModel中获得订阅,这可能不是完美的解决方案。


第二种方法是使用scan运算符。

let nodesStream = Observable.combineLatest(dataFromService, updates).scan(nil) { (previousValues, updates) -> [String] in
    var nodes = previousValues ?? updates.0

    // Filter

    return nodes
}

这种方法可能很难遵循。