swift - 使用组合的自定义更改运算符

标签 swift combine

我希望创建一个行为如下的组合发布者/订阅者/订阅:

struct Change<Value> {
  let new: Value
  let previous: Value?
}

let pub = PassthroughSubject<Int, Never>()

let cancellable = pub
  .change()
  .sink { (change: Change<Int>) -> Void in
    print(change)
  }

pub.send(1) // prints Change(new: 1, previous: nil)
pub.send(2) // prints Change(new: 2, previous: 1)
pub.send(3) // prints Change(new: 3, previous: 2)

无法找到正确的实现方案。我已经制作了自己的发布者/订阅来包装外部 API 调用和排序,但是当需要保留某些状态时无法想出正确的组合,就像本示例中的先前值一样(我认为这意味着您需要自定义订阅者?)

如果由于某种原因 .change() 语法无法使用,则具有相同语义的替代语法也是可以接受的。

最佳答案

您可以从 scanmap 运算符构建 change 运算符,如下所示:

struct Change<Value> {
    var old: Value?
    var new: Value
}

extension Publisher {
    func change() -> Publishers.Map<Publishers.Scan<Self, (Optional<Self.Output>, Optional<Self.Output>)>, Change<Self.Output>> {
        return self
            .scan((Output?.none, Output?.none)) { (state, new) in
                (state.1, .some(new))
            }
            .map { (old, new) in
                Change(old: old, new: new!)
            }
    }
}

演示:

let pub = PassthroughSubject<Int, Never>()
let ticket = pub
    .change()
    .sink { print($0) }

pub.send(1)
// Output: Change<Int>(old: nil, new: 1)

pub.send(2)
// Output: Change<Int>(old: Optional(1), new: 2)

pub.send(3)
// Output: Change<Int>(old: Optional(2), new: 3)

关于swift - 使用组合的自定义更改运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62902789/

相关文章:

ios - SwiftUI - 如何将 EnvironmentObject 传递给 View 模型?

ios - 如何在应用程序委托(delegate)之外注册本地通知?

ios - 在 View 外部触发时如何绑定(bind) SwiftUI.Alert 的呈现?

ios - Swift 数组运行总计 x 项

Swift UiTableView 不重新加载搜索结果

ios - 获取希伯来语字符串的第一个字母

ios - 如何取消Set <AnyCancellable>中的某个特定AnyCancellable?

ios - 可以使用什么 Combine 运算符/方法来加载 "paged API"的所有页面?

swift - 如何在 Swift Joint 中创建自定义链?

swiftui - 更简单的 ViewModel 实现