【问题标题】:Swift Combine: Getting only the first value at subscription?Swift Combine:订阅时只获得第一个价值?
【发布时间】:2021-07-16 21:05:43
【问题描述】:

我有一组传统的UIViewControllers 和UIViews,我将Publisher 传递给:

class MyModel : ObservableObject {
    @Published var product: Product?
}

…

let someView = SomeView(product: self.model.$product)

…

class SomeView : UIView {
    init(product: Published<Product?>.Publisher) {
        self.sub = product.sink { prod in <do stuff when it changes> }
    }

我只需要在视图初始化时对MyModel.product 的属性之一执行一次操作,而不需要 每次product 更新。有没有这样的:

    self.pub = product
        .sinkOnSub { prod in <do when creating this subscription> }
        .sinkRemaining { prod in <do subsequent times> }

【问题讨论】:

  • 出于好奇,如果您只在订阅时需要它,为什么还要在发布者链中进行呢?为什么不直接在self.sub =之前就行呢?
  • @jnpdx 我不知道如何进入实际领域。我所拥有的只是Publisher。有办法吗?
  • 啊,我明白了。有趣的问题。
  • 我会使用 scan 并传递一个元组来指示哪个是第一个。
  • 或者只使用handleEvents 来检测我们何时订阅。

标签: swift combine


【解决方案1】:

您可以创建两个订阅。在第一个处理.first() 值;在第二个中 - 剩余的句柄为 .dropFirst()

var cancellables: Set<AnyCancellable> = []

product
   .first()
   .sink { prod in 
      // handle first
   }
   .store(in: &cancellables)

product
   .dropFirst()
   .sink { prod in 
      // handle remaining
   }
   .store(in: &cancellables)

或者,如果您必须使用相同的 sink,您可以按照 Matt 在 cmets 中的建议:使用 Scan 为每个值附加一个序数:

product
  .scan((0, nil), { (tuple, prod) in 
      (tuple.0 + 1, prod)
  }
  .sink { (n, prod) in
     if n == 1 {
        // handle first
     } else {
        // handle remaining
     }
  }
  .store(in: &cancellables)

【讨论】:

    【解决方案2】:

    订阅正在工作,而令牌存储在可取消项中。当您获得价值时,只需删除令牌即可取消订阅:

    var cancellables: Set<AnyCancellable> = []
    
    product.sink { prod in 
          // handle first
          cancellables = []
       }
       .store(in: &cancellables)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-06-06
      • 1970-01-01
      • 2020-12-19
      • 1970-01-01
      • 2018-09-11
      • 1970-01-01
      • 2019-12-11
      • 1970-01-01
      相关资源
      最近更新 更多