从回调创建发布者

Make a Publisher from a callback

我想包装一个简单的回调,以便它能够用作 Combine Publisher。特别是 NSPersistentContainer.loadPersistentStore 回调,这样我就可以在容器准备就绪时发布。

func createPersistentContainer(name: String) -> AnyPublisher<NSPersistentContainer, Error> {
  // What goes here?
  // Happy path: send output NSPersistentContainer; send completion.
  // Not happy path: send failure Error; send completion.
}

例如,上面给出的 createPersistentContainer 函数的内部结构如何使我能够在我的 AppDelegate.

中执行类似的操作
final class AppDelegate: UIResponder, UIApplicationDelegate {

  let container = createPersistentContainer(name: "DeadlyBattery")
    .assertNoFailure()
    .eraseToAnyPublisher()

  // ...

}

主要归结为,如何将回调包装在 Publisher 中?

Combine 的 Future 似乎是完成这项工作的正确工具。

func createPersistentContainer(name: String) -> AnyPublisher<NSPersistentContainer, Error> {
  let future = Future<NSPersistentContainer, Error> { promise in
    let container = NSPersistentContainer(name: name)
    container.loadPersistentStores { _, error in
      if let error = error {
        promise(.failure(error))
      } else {
        promise(.success(container))
      }
    }
  }
  return AnyPublisher(future)
}

作为之前的发帖人之一@Ryan ,解决方案是使用 Future 发布者。

不过,仅使用 Future 的问题在于它是急切的,这意味着它在创建时开始执行其 promise 闭包,而不是在订阅时开始执行。该挑战的答案是将其包装在 Deferred 发布者中:

func createPersistentContainer(name: String) -> AnyPublisher<NSPersistentContainer, Error> {
    return Deferred {
        Future<NSPersistentContainer, Error> { promise in
            let container = NSPersistentContainer(name: name)
            container.loadPersistentStores { _, error in
                if let error = error {
                    promise(.failure(error))
                } else {
                    promise(.success(container))
                }
            }
        }
    }.eraseToAnyPublisher()
}

NSPersistentContainer 只是围绕核心数据堆栈的便利包装,您最好订阅源代码:

NotificationCenter.default.publisher(for: .NSPersistentStoreCoordinatorStoresDidChange)