struct CoreDataIntormation {
let modelName: String
- let storeFileName: String
- let storeOptions: Dictionary<AnyHashable, Any>
- let storeType: String
- let deleteAndRetry: Bool
+ let fileName: String
+ let options: [AnyHashable: Any]
+ let type: String
+ let tryRemake: Bool
private static let defaultOptions: [AnyHashable: Any] = [
NSMigratePersistentStoresAutomaticallyOption: true,
]
init(_ modelName: String,
- storeFileName: String? = nil,
- storeOptions: [AnyHashable: Any] = defaultOptions,
- storeType: String = NSSQLiteStoreType,
- deleteAndRetry: Bool = false) {
+ fileName: String? = nil,
+ options: [AnyHashable: Any] = defaultOptions,
+ type: String = NSSQLiteStoreType,
+ tryRemake: Bool = false) {
self.modelName = modelName
- self.storeFileName = storeFileName ?? "\(modelName).storedata"
- self.storeOptions = storeOptions
- self.storeType = storeType
- self.deleteAndRetry = deleteAndRetry
+ self.fileName = fileName ?? "\(modelName).storedata"
+ self.options = options
+ self.type = type
+ self.tryRemake = tryRemake
}
}
struct CoreDataCore {
let info: CoreDataIntormation
- let managedObjectModel: NSManagedObjectModel
- let persistentStoreCoordinator: NSPersistentStoreCoordinator
- let parentManagedObjectContext: NSManagedObjectContext
+ let model: NSManagedObjectModel
+ let coordinator: NSPersistentStoreCoordinator
+ let parentContext: NSManagedObjectContext
init(_ info: CoreDataIntormation) {
self.info = info
- let genaratee = try! MocGenerater.genarate(info)
- self.managedObjectModel = genaratee.model
- self.persistentStoreCoordinator = genaratee.coordinator
- self.parentManagedObjectContext = genaratee.moc
+ do {
+ let genaratee = try MocGenerater.genarate(info)
+ (self.model, self.coordinator, self.parentContext) = genaratee
+ } catch {
+ NSApplication.shared().presentError(error)
+ fatalError("CoreDataCore: can not initialize. \(error)")
+ }
}
- func editorManagedObjectContext() -> NSManagedObjectContext {
+ func editorContext() -> NSManagedObjectContext {
let moc = NSManagedObjectContext(concurrencyType: .privateQueueConcurrencyType)
- moc.parent = parentManagedObjectContext
+ moc.parent = parentContext
moc.undoManager = nil
return moc
}
protocol CoreDataProvider {
init(type: CoreDataManagerType)
var core: CoreDataCore { get }
- var managedObjectContext: NSManagedObjectContext { get }
- func saveActionCore()
+ var context: NSManagedObjectContext { get }
+ func save()
}
protocol CoreDataManager {
static var `default`: InstanceType { get }
static func oneTimeEditor() -> InstanceType
- func removeDatabaseFile()
+ func removeDataFile()
}
protocol CoreDataAccessor: CoreDataProvider {
["", "-wal", "-shm"]
.map { name + $0 }
.map { ApplicationDirecrories.support.appendingPathComponent($0) }
- .forEach { removeDatabaseFileAtURL(url: $0) }
+ .forEach { removeDataFile(at: $0) }
}
- private class func removeDatabaseFileAtURL(url: URL) {
+ private class func removeDataFile(at url: URL) {
do {
try FileManager.default.removeItem(at: url)
- }
- catch {
- print("Could not remove file for URL (\(url))");
+ } catch {
+ print("Could not remove file for URL (\(url))")
}
}
}
private class MocGenerater {
- class func genarate(_ info: CoreDataIntormation) throws -> (model: NSManagedObjectModel, coordinator: NSPersistentStoreCoordinator, moc: NSManagedObjectContext) {
- do {
- let model = try createManagedObjectModel(info)
- let coordinator = try createPersistentStoreCoordinator(info, model)
- let moc = createManagedObjectContext(coordinator)
- return (model: model, coordinator: coordinator, moc: moc)
- }
- catch {
- throw error
- }
+ class func genarate(_ info: CoreDataIntormation) throws ->
+ (model: NSManagedObjectModel, coordinator: NSPersistentStoreCoordinator, moc: NSManagedObjectContext) {
+ do {
+ let model = try createModel(info)
+ let coordinator = try getCoordinator(info, model)
+ let moc = createContext(coordinator)
+ return (model: model, coordinator: coordinator, moc: moc)
+ } catch {
+ throw error
+ }
}
- private class func createManagedObjectModel(_ info: CoreDataIntormation) throws -> NSManagedObjectModel {
+ private class func createModel(_ info: CoreDataIntormation) throws -> NSManagedObjectModel {
let modelURL = Bundle.main.url(forResource: info.modelName, withExtension: "momd")!
guard let model = NSManagedObjectModel(contentsOf: modelURL) else {
throw CoreDataError.couldNotCreateModel
}
return model
}
-
- private class func createPersistentStoreCoordinator(_ info: CoreDataIntormation, _ model: NSManagedObjectModel) throws -> NSPersistentStoreCoordinator {
- var failError: NSError? = nil
- var shouldFail = false
- var failureReason = "There was an error creating or loading the application's saved data."
-
+ private class func getCoordinator(_ info: CoreDataIntormation,
+ _ model: NSManagedObjectModel) throws -> NSPersistentStoreCoordinator {
do {
- let p = try ApplicationDirecrories.support.resourceValues(forKeys: [.isDirectoryKey])
- if !p.isDirectory! {
- failureReason = "Expected a folder to store application data, found a file \(ApplicationDirecrories.support.path)."
- shouldFail = true
- }
- }
- catch {
+ return try createCoordinator(info, model)
+ } catch {
let nserror = error as NSError
- if nserror.code == NSFileReadNoSuchFileError {
+ // Data Modelが更新されていたらストアファイルを削除してもう一度
+ if nserror.domain == NSCocoaErrorDomain,
+ (nserror.code == 134130 || nserror.code == 134110),
+ info.tryRemake {
+ self.removeDataFile(info)
do {
- try FileManager.default.createDirectory(at: ApplicationDirecrories.support, withIntermediateDirectories: false, attributes: nil)
+ return try createCoordinator(info, model)
} catch {
- failError = nserror
+ print("Fail crrate NSPersistentStoreCoordinator twice.")
}
- } else {
- failError = nserror
}
+ throw error
}
-
- var coordinator: NSPersistentStoreCoordinator? = nil
- if failError == nil {
- coordinator = NSPersistentStoreCoordinator(managedObjectModel: model)
- let url = ApplicationDirecrories.support.appendingPathComponent(info.storeFileName)
- do {
- try coordinator!.addPersistentStore(ofType: info.storeType, configurationName: nil, at: url, options: info.storeOptions)
- } catch {
- failError = error as NSError
-
- // Data Modelが更新されていたらストアファイルを削除してもう一度
- if failError?.domain == NSCocoaErrorDomain && (failError?.code == 134130 || failError?.code == 134110) && info.deleteAndRetry {
- self.removeDatabaseFile(info)
- do {
- try coordinator!.addPersistentStore(ofType: info.storeType, configurationName: nil, at: url, options: info.storeOptions)
- failError = nil
- }
- catch {
- failError = error as NSError
- }
- }
- }
+ }
+ private class func createCoordinator(_ info: CoreDataIntormation,
+ _ model: NSManagedObjectModel) throws -> NSPersistentStoreCoordinator {
+ if !checkDirectory(ApplicationDirecrories.support) {
+ let failureReason = "Can not use directory \(ApplicationDirecrories.support.path)"
+ throw CoreDataError.couldNotCreateCoordinator(failureReason)
}
- if shouldFail || (failError != nil) {
- if let error = failError {
- NSApplication.shared().presentError(error)
- }
- throw CoreDataError.couldNotCreateCoordinator(failureReason)
+ let coordinator: NSPersistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: model)
+ let url = ApplicationDirecrories.support.appendingPathComponent(info.fileName)
+ do {
+ try coordinator.addPersistentStore(ofType: info.type,
+ configurationName: nil,
+ at: url,
+ options: info.options)
+ } catch {
+ throw error
}
- return coordinator!
+ return coordinator
}
- private class func createManagedObjectContext(_ coordinator: NSPersistentStoreCoordinator) -> NSManagedObjectContext {
+ private class func createContext(_ coordinator: NSPersistentStoreCoordinator) -> NSManagedObjectContext {
let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
moc.persistentStoreCoordinator = coordinator
moc.undoManager = nil
return moc
}
- private class func removeDatabaseFile(_ info: CoreDataIntormation) {
- CoreDataRemover.remove(name: info.storeFileName)
+ private class func removeDataFile(_ info: CoreDataIntormation) {
+ CoreDataRemover.remove(name: info.fileName)
}
}
extension CoreDataManager where Self: CoreDataProvider {
- func removeDatabaseFile() {
- CoreDataRemover.remove(name: self.core.info.storeFileName)
+ func removeDataFile() {
+ CoreDataRemover.remove(name: self.core.info.fileName)
}
}
extension CoreDataProvider {
- func saveActionCore() {
- if !managedObjectContext.commitEditing() {
- NSLog("\(String(describing: type(of: self))) unable to commit editing before saveing")
+ func save() {
+ if !context.commitEditing() {
+ print("\(String(describing: type(of: self))) unable to commit editing before saveing")
return
}
- do { try managedObjectContext.save() }
- catch { presentOnMainThread(error) }
- if let p = managedObjectContext.parent {
+ do {
+ try context.save()
+ } catch { presentOnMainThread(error) }
+ if let p = context.parent {
p.performAndWait {
- do { try p.save() }
- catch { self.presentOnMainThread(error) }
+ do {
+ try p.save()
+ } catch { self.presentOnMainThread(error) }
}
}
}
extension CoreDataAccessor {
func insertNewObject<T>(for entity: Entity<T>) -> T? {
return NSEntityDescription
- .insertNewObject(forEntityName: entity.name
- , into: managedObjectContext) as? T
+ .insertNewObject(forEntityName: entity.name,
+ into: context) as? T
}
func delete(_ object: NSManagedObject) {
- managedObjectContext.delete(object)
+ context.delete(object)
}
func object(with objectId: NSManagedObjectID) -> NSManagedObject {
- return managedObjectContext.object(with: objectId)
+ return context.object(with: objectId)
}
- func objects<T>(with entity: Entity<T>, sortDescriptors: [NSSortDescriptor]? = nil, predicate: NSPredicate? = nil) throws -> [T] {
+ func objects<T>(with entity: Entity<T>,
+ sortDescriptors: [NSSortDescriptor]? = nil,
+ predicate: NSPredicate? = nil) throws -> [T] {
let req = NSFetchRequest<T>(entityName: entity.name)
req.sortDescriptors = sortDescriptors
req.predicate = predicate
- return try managedObjectContext.fetch(req)
+ return try context.fetch(req)
}
}