【问题标题】:Swift Combine: Merge publishers of different typesSwift Combine:合并不同类型的发布者
【发布时间】:2021-07-10 19:17:56
【问题描述】:

我正在尝试合并多个不同类型的发布者。

我有一个字符串类型的发布者和一个类型的发布者,但是当我使用MergeManyCombineLatest 合并它们时,我得到一个类型不匹配的错误。

是否可以合并不同类型的发布者?请看下面的代码示例:

@Published var str1: String?
@Published var str2: String?
@Published var image: Image?
        
Publishers.MergeMany($str1, $str2, $image)
    .removeDuplicates()
    .sink { _ in
        //...
    }
    .store(in: &bag)

【问题讨论】:

  • 我认为一个重要的因素是你期望在sink 中得到什么——_ 是否暗示你实际上不需要在那里获取参数并且你只是更关心其中一个已更新的事实?
  • 是的,我只关心其中一个发生了变化。我忘记包含在我的代码示例中的一件事是,如果可能,我想删除任何重复项,但如果有另一种实现方式,则不需要。
  • 那里有问题,你为什么要发布Image?那是一个 SwiftUI 视图,你不太可能从中得到有用的东西。还是您尝试发布 UIImage

标签: swift swiftui combine


【解决方案1】:

假设您没有其他@Published 属性,最简单的方法是使用objectWillChange

self.objectWillChange
        .receive(on: RunLoop.main)
        .sink {
            print("objectWillChange...", self.str1, self.str2, self.image)
        }
        .store(in: &bag)

但是,这不会为您提供您在 cmets 中提到的删除重复项。

如果你愿意,你可以让事情变得更复杂一些:

Publishers.MergeMany(
            $str1.dropFirst().removeDuplicates().map({ _ in }).eraseToAnyPublisher(),
            $str2.dropFirst().removeDuplicates().map({ _ in }).eraseToAnyPublisher(),
            $image.dropFirst().removeDuplicates().map({ _ in }).eraseToAnyPublisher()
        )
        .receive(on: RunLoop.main)
        .sink {
            print("MergeMany...", self.str1, self.str2, self.image)
        }
        .store(in: &bag)

(可能有比我的map. { _ in } 更漂亮的方式去掉返回类型)

上述方法似乎可以有效地删除单个重复元素,并且仅在其中一个发生更改时触发sink

【讨论】:

    【解决方案2】:

    @jnpdx 的回答完成了工作。我专注于 OP 提出的这个问题:

    有没有办法合并不同类型的发布者?

    了解 Merge 和 CombineLatest 运算符之间的区别很重要,因为它们在语义上完全不同。

    查看 RxMarbles 的 MergeCombineLatest。 Merge 要求内部发布者具有相同的 Output 并在每次发出时发出单个值。 CombineLatest 发布一个元组,其中包含每个内部发布者的最新值。

    我会这样写:

    @Published var str1: String?
    @Published var str2: String?
    @Published var image: Image?
        
    func setUpBindings() {
        Publishers.CombineLatest3($str1, $str2, $image)
            .sink { _ in 
                //...
            }
            .store(in: &bag)
    }
    

    由于元组(目前)不符合 Equatable 标准,因此您无法在生成的发布者上利用 removeDuplicates()

    就像@jnpdx 写的那样,一种方法可能是将内部的.removeDuplicates() 拉到每个发布者那里。

    Publishers.CombineLatest3(
        $str1.removeDuplicates(),
        $str2.removeDuplicates(), 
        $image.removeDuplicates()
    )
        .sink { (str1, str2, image) in
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多