I want to achieve the following: Whenever someone triggers a CoreData save (ie. NSManagedObjectContextDidSave notification gets sent), I\'d like to perform some
You can create a Publisher which informs you when something relevant for you in Core Data has changed.
I wrote an article on this. Combine, Publishers and Core Data.
import Combine
import CoreData
import Foundation
class CDPublisher: NSObject, NSFetchedResultsControllerDelegate, Publisher where Entity: NSManagedObject {
typealias Output = [Entity]
typealias Failure = Error
private let request: NSFetchRequest
private let context: NSManagedObjectContext
private let subject: CurrentValueSubject<[Entity], Failure>
private var resultController: NSFetchedResultsController?
private var subscriptions = 0
init(request: NSFetchRequest, context: NSManagedObjectContext) {
if request.sortDescriptors == nil { request.sortDescriptors = [] }
self.request = request
self.context = context
subject = CurrentValueSubject([])
super.init()
}
func receive(subscriber: S)
where S: Subscriber, CDPublisher.Failure == S.Failure, CDPublisher.Output == S.Input {
var start = false
synchronized(self) {
subscriptions += 1
start = subscriptions == 1
}
if start {
let controller = NSFetchedResultsController(fetchRequest: request, managedObjectContext: context,
sectionNameKeyPath: nil, cacheName: nil)
controller.delegate = self
do {
try controller.performFetch()
let result = controller.fetchedObjects ?? []
subject.send(result)
} catch {
subject.send(completion: .failure(error))
}
resultController = controller as? NSFetchedResultsController
}
CDSubscription(fetchPublisher: self, subscriber: AnySubscriber(subscriber))
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController) {
let result = controller.fetchedObjects as? [Entity] ?? []
subject.send(result)
}
private func dropSubscription() {
objc_sync_enter(self)
subscriptions -= 1
let stop = subscriptions == 0
objc_sync_exit(self)
if stop {
resultController?.delegate = nil
resultController = nil
}
}
private class CDSubscription: Subscription {
private var fetchPublisher: CDPublisher?
private var cancellable: AnyCancellable?
@discardableResult
init(fetchPublisher: CDPublisher, subscriber: AnySubscriber