Reputation: 6662
I would like to wrap a simple callback so that it would be able to be used as a Combine Publisher
. Specifically the NSPersistentContainer.loadPersistentStore callback so I can publish when the container is ready to go.
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.
}
For instance, what would the internals of a function, createPersistentContainer
given above, look like to enable me to do something like this in my AppDelegate
.
final class AppDelegate: UIResponder, UIApplicationDelegate {
let container = createPersistentContainer(name: "DeadlyBattery")
.assertNoFailure()
.eraseToAnyPublisher()
// ...
}
Mostly this boils down to, how do you wrap a callback in a Publisher
?
Upvotes: 7
Views: 4167
Reputation: 30746
NSPersistentContainer
is just a convenience wrapper around a core data stack, you would be better off subscribing at the source:
NotificationCenter.default.publisher(for: .NSPersistentStoreCoordinatorStoresDidChange)
Upvotes: -2
Reputation: 1807
As one of the previous posters @Ryan pointed out, the solution is to use the Future
publisher.
The problem of using only the Future
, though, is that it is eager, which means that it starts executing its promise closure at the moment of creation, not when it is subscribed to. The answer to that challenge is to wrap it in the Deferred
publisher:
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()
}
Upvotes: 17
Reputation: 6662
It seems that Combine's Future
is the correct tool for the job.
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)
}
Upvotes: 10