Skip to content

Instantly share code, notes, and snippets.

@insidegui
Created August 6, 2020 12:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save insidegui/8f6a4409609013c2e847b440c553ea47 to your computer and use it in GitHub Desktop.
Save insidegui/8f6a4409609013c2e847b440c553ea47 to your computer and use it in GitHub Desktop.
import UIKit
import Combine
import CoreData
import OSLog
public typealias CoreDataModelTransformer<T: NSManagedObject, M: Hashable> = (T) -> M?
public final class CoreDataAdapter<T: NSManagedObject, M: Hashable>: NSObject, NSFetchedResultsControllerDelegate {
private let logger = Logger(subsystem: "codes.rambo.CombineCoreData", category: "CoreDataAdapter")
public typealias SnapshotType = NSDiffableDataSourceSnapshot<Int, M>
public let container: NSPersistentContainer
public var request: NSFetchRequest<T> {
didSet {
setupController()
}
}
public let transformer: CoreDataModelTransformer<T,M>
@Published public private(set) var snapshot = SnapshotType()
private var controller: NSFetchedResultsController<T>
public init(with request: NSFetchRequest<T>, in container: NSPersistentContainer, transformer: @escaping CoreDataModelTransformer<T,M>) {
self.container = container
self.request = request
self.transformer = transformer
self.controller = NSFetchedResultsController(
fetchRequest: request,
managedObjectContext: container.viewContext,
sectionNameKeyPath: nil,
cacheName: "\(String(describing: T.self))"
)
super.init()
setupController()
}
private func setupController() {
controller = NSFetchedResultsController(
fetchRequest: request,
managedObjectContext: container.viewContext,
sectionNameKeyPath: nil,
cacheName: nil
)
do {
controller.delegate = self
try controller.performFetch()
updateSnapshot()
} catch {
assertionFailure("Failed to start NSFetchedResultsController: \(String(describing: error))")
logger.fault("Couldn't start the fetched results controller: \(String(describing: error), privacy: .public)")
}
}
public func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
logger.debug("\(#function, privacy: .public)")
updateSnapshot()
}
private var managedObjects: [T] { controller.fetchedObjects ?? [] }
public private(set) var models: [M] = []
private let updateQueue = DispatchQueue(label: "AdapterUpdate", qos: .userInteractive)
private func updateSnapshot() {
updateQueue.async {
let ctx = self.container.newBackgroundContext()
let objs = self.managedObjects.compactMap { ctx.object(with: $0.objectID) as? T }
self.models = objs.compactMap(self.transformer)
var snap = NSDiffableDataSourceSnapshot<Int, M>()
snap.appendSections([0])
snap.appendItems(self.models)
DispatchQueue.main.async {
self.snapshot = snap
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment