Swift 合并尚未发送值的发布商

Dam*_*fex 3 swift combine

我有一个发布者,需要在日期变化时重新评估,但应该在任何其他时间继续发出值。

\n

因此,我认为我可以使用NotificationCenter发布者来UIApplication.significantTimeChangeNotification发送通知,并将其与我的发布者组合起来,以便组合发射过程可以在数据更改或日期更改时重新运行,从而重新评估地图过滤器。请参阅下面该代码的粗略轮廓。

\n

NotificationCenter问题是,在设置时没有发布事件,因此,以下map等调用都不会实际评估。merge(with:)不会起作用,因为两个出版商发布不同的类型,但是combineLatest(_:)zip(_:)两个发布者都发出单个事件之前,两者都不会发出事件。

\n

我可以通过添加来验证我的代码是否按预期运行NotificationCenter.default.post(name: UIApplication.significantTimeChangeNotification, object: nil),但这是不可取的,因为它可能会向应用程序的其他区域发出信号,表明实际时间更改已发生,而实际上时间更改尚未发生

\n
private func todaysDate() -> String {\n    let formatter = DateFormatter()\n    formatter.dateFormat = "YYYY-MM-dd"\n    return formatter.string(from: Date())\n}\n\n@Published var entities: [MyEntity]\n\nlet dayChangePublisher = NotificationCenter.default\n    .publisher(for: UIApplication.significantTimeChangeNotification)\n\n$entities.combineLatest(dayChangePublisher)\n    .map(\\.0) // Only pass on the entity for further operations\n    .map { entities -> MyEntity? in\n        let today = todaysDate()\n        return entities?.first(where: { $0.id == today })\n    }\n    ...remainder of combine code\n\n
Run Code Online (Sandbox Code Playgroud)\n

当前的 Swift 组合框架可以实现发布者和事件评估的结合吗?就像我期望的行为一样merge(with:),但发布者发出两种不同的类型。

\n

编辑:\n我找到了一种解决方案,将通知发布者映射到 nil 数组

\n
let dayChangePublisher = NotificationCenter.default\n    .publisher(for: UIApplication.significantTimeChangeNotification)\n    .map { _ \xe2\x9e\x9d [MyEntity]? in\n        return nil\n    }\n
Run Code Online (Sandbox Code Playgroud)\n

然后使用mergecompactMap来避免传递任何 nil 值

\n
let mergedPub = repo.$entities\n        .merge(with: dayChangePublisher)\n        .compactMap { entity -> MyEntity? in\n            let today = todaysDate()\n            return entities?.first { $0.id == today }\n        }\n        .share()\n
Run Code Online (Sandbox Code Playgroud)\n

它有效,但如果有人有更好的解决方案,可能有点麻烦?

\n

New*_*Dev 6

如果我理解你的问题,你需要一个combineLatest不会因为没有来自发布者之一的初始值而被阻止的。

您可以通过.prepend(value)操作员来实现这一点。在这种情况下,由于您不关心实际值,因此首先映射到Void,然后在前面添加Void. 它会像这样工作:

let dayChangePublisher = NotificationCenter.default
    .publisher(for: UIApplication.significantTimeChangeNotification)

$entities.combineLatest(
   dayChangePublisher
      .map { _ in }
      .prepend(()) // make sure to prepend a () value
    )
    .map(\.0) // Only pass on the entity for further operations
    .map { entities -> MyEntity? in
        let today = todaysDate()
        return entities?.first(where: { $0.id == today })
    }
    //... 
Run Code Online (Sandbox Code Playgroud)