Swift 将两个处理程序合并为一个 属性

Swift Combine two handlers for one property

我有一个使用 UITableViewDiffableDataSourceUIViewController。我有一个这个控制器的视图模型,它看起来像:

class ListViewModel {
    @Published private(set) var items: [Item] = []
    
    func load(params: [String: Any] = [:]) {
        WebRepo().index(params: params, completion: { [weak self] (items, error) in
            self?.items = items
        })
    }
    
    func deleteFirst() {
        self.items.remove(object: self.items.first)
    }
}

在我的 VC 中,我有这样的绑定:

self.viewModel.$items.sink { [weak self] (scenes) in
    self?.update(items: items, animated: false)
}.store(in: &self.subscriptions)

所以,当我调用我的视图模型的 load 方法时 - 我想做 self?.update(items: items, animated: false),但是当我调用 deleteFirst - 我想要 self?.update(items: items, animated: true).

我对 Reactive 和 Combine 很陌生,所以不确定处理这个问题的正确方法是什么。 我可以将 isReset 属性 添加到我的视图模型并将 load 方法更改为:

    func load(params: [String: Any] = [:]) {
        WebRepo().index(params: params, completion: { [weak self] (items, error) in
            self?.isReset = true
            self?.items = items
            self?.isReset = false
        })
    }

sink 中只需检查这个 属性,但它看起来不适合我。

这是一种思考方式。不要发布 items,而是使用输出类型为元组 ([Items], Bool) 的 PassthroughSubject。并且视图控制器订阅了该主题。

现在,当你调用load时,用(items, false)调用传递对象的send,但是当你调用delete时,调用传递对象的send ] 与 (items, true).

换句话说,让您的发布商负责发布所有下游需要知道该做什么的信息。

您可能认为这种方法相当极端,但是将事物聚集成一个元组以便将多条信息传递到管道中是正常行为。真的,这相当于用两个参数调用一个方法。


另一种可能是下游考虑该发布者发布了多少次。例如,如果 ViewModel 将只调用一次 load,这将起作用。如果是这种情况,下游管道将能够使用运算符(例如 scanfirst 或其他)来区分管道中的第一个值(这意味着我们不想动画)从任何后续值(我们想要动画的地方)。


另一种思考方式是将责任完全推给构建快照的人。如果 diffable 数据源的快照为空,则它没有数据,我们不想设置动画。如果不为空,我们确实想要动画。同样,这只有在适用于您的目的时才有效。