4

我想包装一个简单的回调,以便它可以用作 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()

  // ...

}

大多数情况下,这归结为,你如何将回调包装在 a 中Publisher

4

3 回答 3

9

正如之前的一张海报@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()
}
于 2020-03-10T16:46:37.263 回答
7

看来,Combine'sFuture是完成这项工作的正确工具。

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)
}
于 2019-07-03T17:25:39.633 回答
-1

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

NotificationCenter.default.publisher(for: .NSPersistentStoreCoordinatorStoresDidChange)

于 2020-07-28T14:05:30.087 回答