// // Managed.swift // CoreDataStack // // Created by Cirno MainasuK on 2020-8-6. // import Foundation import CoreData public protocol Managed: NSFetchRequestResult { static var entityName: String { get } static var defaultSortDescriptors: [NSSortDescriptor] { get } } extension Managed { public static var defaultSortDescriptors: [NSSortDescriptor] { return [] } public static var sortedFetchRequest: NSFetchRequest { let request = NSFetchRequest(entityName: entityName) request.sortDescriptors = defaultSortDescriptors return request } } extension NSManagedObjectContext { public func insertObject() -> T where T: Managed { guard let object = NSEntityDescription.insertNewObject(forEntityName: T.entityName, into: self) as? T else { fatalError("Wrong object type") } return object } } extension Managed where Self: NSManagedObject { public static var entityName: String { return entity().name! } } extension Managed where Self: NSManagedObject { public static func findOrCreate(in context: NSManagedObjectContext, matching predicate: NSPredicate, configure: (Self) -> Void) -> Self { guard let object = findOrFetch(in: context, matching: predicate) else { let newObject: Self = context.insertObject() configure(newObject) return newObject } return object } public static func findOrFetch(in context: NSManagedObjectContext, matching predicate: NSPredicate) -> Self? { guard let object = materializedObject(in: context, matching: predicate) else { return fetch(in: context) { request in request.predicate = predicate request.returnsObjectsAsFaults = false request.fetchLimit = 1 }.first } return object } public static func materializedObject(in context: NSManagedObjectContext, matching predicate: NSPredicate) -> Self? { for object in context.registeredObjects where !object.isFault { guard let result = object as? Self, predicate.evaluate(with: result) else { continue } return result } return nil } public static func fetch(in context: NSManagedObjectContext, configurationBlock: (NSFetchRequest) -> Void = { _ in }) -> [Self] { let request = NSFetchRequest(entityName: Self.entityName) configurationBlock(request) return try! context.fetch(request) } }