WIP: SQLiteStore implementation

This commit is contained in:
John Rommel Estropia
2016-03-04 07:51:35 +09:00
parent b283fbf5ab
commit 3c514830d9
7 changed files with 331 additions and 106 deletions

View File

@@ -219,6 +219,10 @@
B5D372841A39CD6900F583D9 /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B5D372821A39CD6900F583D9 /* Model.xcdatamodeld */; };
B5D372861A39CDDB00F583D9 /* TestEntity1.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D372851A39CDDB00F583D9 /* TestEntity1.swift */; };
B5D39A0219FD00C9000E91BB /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5D39A0119FD00C9000E91BB /* Foundation.framework */; };
B5D3F6451C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D3F6441C887C0A00C7492A /* LegacySQLiteStore.swift */; };
B5D3F6461C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D3F6441C887C0A00C7492A /* LegacySQLiteStore.swift */; };
B5D3F6471C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D3F6441C887C0A00C7492A /* LegacySQLiteStore.swift */; };
B5D3F6481C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D3F6441C887C0A00C7492A /* LegacySQLiteStore.swift */; };
B5D5E0CF1A4D6AAB006468AF /* TestEntity2.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D5E0CE1A4D6AAB006468AF /* TestEntity2.swift */; };
B5E834B91B76311F001D3D50 /* BaseDataTransaction+Importing.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E834B81B76311F001D3D50 /* BaseDataTransaction+Importing.swift */; };
B5E834BB1B7691F3001D3D50 /* Functions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E834BA1B7691F3001D3D50 /* Functions.swift */; };
@@ -344,6 +348,7 @@
B5D372831A39CD6900F583D9 /* Model.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Model.xcdatamodel; sourceTree = "<group>"; };
B5D372851A39CDDB00F583D9 /* TestEntity1.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestEntity1.swift; sourceTree = "<group>"; };
B5D39A0119FD00C9000E91BB /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
B5D3F6441C887C0A00C7492A /* LegacySQLiteStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacySQLiteStore.swift; sourceTree = "<group>"; };
B5D5E0CE1A4D6AAB006468AF /* TestEntity2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestEntity2.swift; sourceTree = "<group>"; };
B5D9C8F61B160ED200E64F0E /* CoreStore.podspec */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; path = CoreStore.podspec; sourceTree = SOURCE_ROOT; };
B5E834B81B76311F001D3D50 /* BaseDataTransaction+Importing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "BaseDataTransaction+Importing.swift"; sourceTree = "<group>"; };
@@ -709,6 +714,7 @@
B5FE4DA11C8481E100FA6A91 /* StorageInterface.swift */,
B5FE4DA61C84FB4400FA6A91 /* InMemoryStore.swift */,
B5FE4DAB1C85D44E00FA6A91 /* SQLiteStore.swift */,
B5D3F6441C887C0A00C7492A /* LegacySQLiteStore.swift */,
);
path = PersistentStores;
sourceTree = "<group>";
@@ -997,6 +1003,7 @@
B504D0D61B02362500B2BBB1 /* CoreStore+Setup.swift in Sources */,
B5D1E22C19FA9FBC003B2874 /* NSError+CoreStore.swift in Sources */,
B5E84F131AFF847B0064E85B /* Where.swift in Sources */,
B5D3F6451C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */,
B54A6A551BA15F2A007870FD /* FetchedResultsControllerDelegate.swift in Sources */,
B5A261211B64BFDB006EB6D3 /* MigrationType.swift in Sources */,
B5E84F141AFF847B0064E85B /* DataStack+Querying.swift in Sources */,
@@ -1085,6 +1092,7 @@
82BA18A51C4BBD2200A0916E /* CoreStore+Setup.swift in Sources */,
82BA18BD1C4BBD4A00A0916E /* GroupBy.swift in Sources */,
B5C976E41C6C9F9A00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */,
B5D3F6461C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */,
82BA18B31C4BBD3900A0916E /* ImportableUniqueObject.swift in Sources */,
82BA18A11C4BBD1D00A0916E /* CoreStore.swift in Sources */,
82BA18CF1C4BBD7100A0916E /* Functions.swift in Sources */,
@@ -1158,6 +1166,7 @@
B52DD1AB1BE1F93900949AFE /* From.swift in Sources */,
B52DD1BF1BE1F94600949AFE /* AssociatedObjects.swift in Sources */,
B52DD1A11BE1F92C00949AFE /* DataStack+Transaction.swift in Sources */,
B5D3F6481C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */,
B52DD19E1BE1F92C00949AFE /* AsynchronousDataTransaction.swift in Sources */,
B52DD1981BE1F92500949AFE /* CoreStore+Setup.swift in Sources */,
B52DD1941BE1F92500949AFE /* CoreStore.swift in Sources */,
@@ -1234,6 +1243,7 @@
B56321891BD65216006C9394 /* AsynchronousDataTransaction.swift in Sources */,
B56321831BD65216006C9394 /* CoreStore+Setup.swift in Sources */,
B5C976E51C6C9F9B00B1AF90 /* UnsafeDataTransaction+Observing.swift in Sources */,
B5D3F6471C887C0A00C7492A /* LegacySQLiteStore.swift in Sources */,
B563217F1BD65216006C9394 /* CoreStore.swift in Sources */,
B56321911BD65216006C9394 /* BaseDataTransaction+Importing.swift in Sources */,
B56321941BD65216006C9394 /* CoreStore+Querying.swift in Sources */,

View File

@@ -83,13 +83,21 @@ public extension CoreStore {
// MARK: Deprecated
/**
Deprecated. Use `addStorageAndWait(_:)` by passing a `InMemoryStore` instance.
*/
@available(*, deprecated=2.0.0, obsoleted=2.0.0, message="Use addStorageAndWait(_:) by passing an InMemoryStore instance.")
public static func addInMemoryStoreAndWait(configuration configuration: String? = nil) throws -> NSPersistentStore {
return try self.defaultStack.addInMemoryStoreAndWait(configuration: configuration)
}
@available(*, deprecated=2.0.0, message="Use addStorageAndWait(_:) by passing an SQLiteStore instance. Note that the previous default directory for the SQLite file was in the \"Application Support\" directory (or the \"Caches\" directory on tvOS), but the new addStorageAndWait(_:configuration:) method's default directory is now in the \"Application Support/<bundle id>\" directory (or the \"Caches/<bundle id>\" directory on tvOS)")
/**
Deprecated. Use `addStorageAndWait(_:)` by passing a `LegacySQLiteStore` instance.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was using this method prior to 2.0.0, make sure to use `LegacySQLiteStore`.
*/
@available(*, deprecated=2.0.0, message="Use addStorageAndWait(_:) by passing a LegacySQLiteStore instance. Warning: The default SQLite file location for the LegacySQLiteStore and SQLiteStore are different. If the app was using this method prior to 2.0.0, make sure to use LegacySQLiteStore.")
public static func addSQLiteStoreAndWait(fileName fileName: String, configuration: String? = nil, resetStoreOnModelMismatch: Bool = false) throws -> NSPersistentStore {
return try self.defaultStack.addSQLiteStoreAndWait(
@@ -99,10 +107,15 @@ public extension CoreStore {
)
}
@available(*, deprecated=2.0.0, message="Use addStorageAndWait(_:) by passing an SQLiteStore instance. Note that the previous default URL for the SQLite file was in the \"Application Support/<bundle name>.sqlite\" directory (or the \"Caches/<bundle name>.sqlite\" directory on tvOS), but the new addStorageAndWait(_:configuration:) method's default directory is now in the \"Application Support/<bundle id>/<bundle name>.sqlite\" directory (or the \"Caches/<bundle id>/<bundle name>.sqlite\" directory on tvOS)")
public static func addSQLiteStoreAndWait(fileURL fileURL: NSURL = DataStack.DeprecatedDefaults.defaultSQLiteStoreURL, configuration: String? = nil, resetStoreOnModelMismatch: Bool = false) throws -> NSPersistentStore {
/**
Deprecated. Use `addStorageAndWait(_:)` by passing a `LegacySQLiteStore` instance.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was using this method prior to 2.0.0, make sure to use `LegacySQLiteStore`.
*/
@available(*, deprecated=2.0.0, message="Use addStorageAndWait(_:) by passing a LegacySQLiteStore instance. Warning: The default SQLite file location for the LegacySQLiteStore and SQLiteStore are different. If the app was using this method prior to 2.0.0, make sure to use LegacySQLiteStore.")
public static func addSQLiteStoreAndWait(fileURL fileURL: NSURL = LegacySQLiteStore.legacyDefaultFileURL, configuration: String? = nil, resetStoreOnModelMismatch: Bool = false) throws -> NSPersistentStore {
return try self.addSQLiteStoreAndWait(
return try self.defaultStack.addSQLiteStoreAndWait(
fileURL: fileURL,
configuration: configuration,
resetStoreOnModelMismatch: resetStoreOnModelMismatch

View File

@@ -122,8 +122,33 @@ public final class DataStack {
CoreStore.assert(
store.internalStore == nil,
"The specified store was already added to the data stack: \(store)"
"The specified \"\(typeName(store))\" was already added to the data stack: \(store)"
)
CoreStore.assert(
T.validateStoreURL(store.storeURL),
"The specified store URL for the \"\(typeName(store))\" is invalid: \"\(store.storeURL)\""
)
// TODO: check
// if let store = coordinator.persistentStoreForURL(fileURL) {
//
// guard store.type == NSSQLiteStoreType
// && store.configurationName == (configuration ?? Into.defaultConfigurationName) else {
//
// let error = NSError(coreStoreErrorCode: .DifferentPersistentStoreExistsAtURL)
// CoreStore.handleError(
// error,
// "Failed to add SQLite \(typeName(NSPersistentStore)) at \"\(fileURL)\" because a different \(typeName(NSPersistentStore)) at that URL already exists."
// )
// throw error
// }
//
// GCDQueue.Main.async {
//
// completion(PersistentStoreResult(store))
// }
// return nil
// }
do {
@@ -145,6 +170,8 @@ public final class DataStack {
// MARK: Internal
internal static let applicationName = (NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleName") as? String) ?? "CoreData"
internal let coordinator: NSPersistentStoreCoordinator
internal let rootSavingContext: NSManagedObjectContext
internal let mainContext: NSManagedObjectContext
@@ -243,9 +270,7 @@ public final class DataStack {
}
// MARK: Private]
private static let applicationName = (NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleName") as? String) ?? "CoreData"
// MARK: Private
private var configurationStoreMapping = [String: NSPersistentStore]()
private var entityConfigurationsMapping = [String: Set<String>]()
@@ -259,24 +284,9 @@ public final class DataStack {
// MARK: Deprecated
internal enum DeprecatedDefaults {
#if os(tvOS)
internal static let systemDirectorySearchPath = NSSearchPathDirectory.CachesDirectory
#else
internal static let systemDirectorySearchPath = NSSearchPathDirectory.ApplicationSupportDirectory
#endif
internal static let defaultDirectory = NSFileManager.defaultManager().URLsForDirectory(
DeprecatedDefaults.systemDirectorySearchPath,
inDomains: .UserDomainMask
).first!
internal static let defaultSQLiteStoreURL = DeprecatedDefaults.defaultDirectory
.URLByAppendingPathComponent(DataStack.applicationName, isDirectory: false)
.URLByAppendingPathExtension("sqlite")
}
/**
Deprecated. Use `addStorageAndWait(_:)` by passing a `InMemoryStore` instance.
*/
@available(*, deprecated=2.0.0, message="Use addStorageAndWait(_:) by passing an InMemoryStore instance.")
public func addInMemoryStoreAndWait(configuration configuration: String? = nil) throws -> NSPersistentStore {
@@ -284,15 +294,17 @@ public final class DataStack {
return storage.internalStore!
}
@available(*, deprecated=2.0.0, message="Use addStorageAndWait(_:) by passing an SQLiteStore instance. Note that the previous default directory for the SQLite file was in the \"Application Support\" directory (or the \"Caches\" directory on tvOS), but the new addStorageAndWait(_:configuration:) method's default directory is now in the \"Application Support/<bundle id>\" directory (or the \"Caches/<bundle id>\" directory on tvOS)")
/**
Deprecated. Use `addStorageAndWait(_:)` by passing a `LegacySQLiteStore` instance.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was using this method prior to 2.0.0, make sure to use `LegacySQLiteStore`.
*/
@available(*, deprecated=2.0.0, message="Use addStorageAndWait(_:) by passing a LegacySQLiteStore instance. Warning: The default SQLite file location for the LegacySQLiteStore and SQLiteStore are different. If the app was using this method prior to 2.0.0, make sure to use LegacySQLiteStore.")
public func addSQLiteStoreAndWait(fileName fileName: String, configuration: String? = nil, resetStoreOnModelMismatch: Bool = false) throws -> NSPersistentStore {
let storage = try self.addStorageAndWait(
SQLiteStore(
fileURL: DeprecatedDefaults.defaultDirectory.URLByAppendingPathComponent(
fileName,
isDirectory: false
),
LegacySQLiteStore(
fileName: fileName,
configuration: configuration,
resetStoreOnModelMismatch: resetStoreOnModelMismatch
)
@@ -301,16 +313,16 @@ public final class DataStack {
}
/**
Deprecated. Use `addStorageAndWait(_:)` by passing an `SQLiteStore` instance.
Deprecated. Use `addStorageAndWait(_:)` by passing a `LegacySQLiteStore` instance.
- Warning: The previous default URL for the SQLite file was "Application Support/\<bundle name\>.sqlite" ("Caches/\<bundle name\>.sqlite" directory on tvOS), but the new `addStorageAndWait(_:)` method's default URL is now "Application Support/\<bundle id\>/\<bundle name\>.sqlite" ("Caches/\<bundle id\>/\<bundle name\>.sqlite" on tvOS) to better comply with per Apple's guidelines.
- Warning: The default SQLite file location for the `LegacySQLiteStore` and `SQLiteStore` are different. If the app was using this method prior to 2.0.0, make sure to use `LegacySQLiteStore`.
*/
@available(*, deprecated=2.0.0, message="Use addStorageAndWait(_:) by passing an SQLiteStore instance. Warning: the previous default URL for the SQLite file was \"Application Support/<bundle name>.sqlite\" (\"Caches/<bundle name>.sqlite\" directory on tvOS), but the new addStorageAndWait(_:configuration:) method's default URL is now \"Application Support/<bundle id>/<bundle name>.sqlite\" (\"Caches/<bundle id>/<bundle name>.sqlite\" on tvOS) to better comply with per Apple's guidelines,")
public func addSQLiteStoreAndWait(fileURL fileURL: NSURL = DeprecatedDefaults.defaultSQLiteStoreURL, configuration: String? = nil, resetStoreOnModelMismatch: Bool = false) throws -> NSPersistentStore {
@available(*, deprecated=2.0.0, message="Use addStorageAndWait(_:) by passing a LegacySQLiteStore instance. Warning: The default SQLite file location for the LegacySQLiteStore and SQLiteStore are different. If the app was using this method prior to 2.0.0, make sure to use LegacySQLiteStore.")
public func addSQLiteStoreAndWait(fileURL fileURL: NSURL = LegacySQLiteStore.legacyDefaultFileURL, configuration: String? = nil, resetStoreOnModelMismatch: Bool = false) throws -> NSPersistentStore {
let storage = try self.addStorageAndWait(
SQLiteStore(
fileURL: DeprecatedDefaults.defaultSQLiteStoreURL,
LegacySQLiteStore(
fileURL: fileURL,
configuration: configuration,
resetStoreOnModelMismatch: resetStoreOnModelMismatch
)

View File

@@ -48,11 +48,45 @@ public class InMemoryStore: StorageInterface, DefaultInitializableStore {
public static let storeType = NSInMemoryStoreType
public static func validateStoreURL(storeURL: NSURL?) -> Bool {
return storeURL == nil
}
public let storeURL: NSURL? = nil
public let configuration: String?
public let storeOptions: [String: AnyObject]? = nil
public var internalStore: NSPersistentStore?
public func addToPersistentStoreCoordinatorSynchronously(coordinator: NSPersistentStoreCoordinator) throws -> NSPersistentStore {
return try coordinator.addPersistentStoreSynchronously(
self.dynamicType.storeType,
configuration: self.configuration,
URL: self.storeURL,
options: self.storeOptions
)
}
public func addToPersistentStoreCoordinatorAsynchronously(coordinator: NSPersistentStoreCoordinator, mappingModelBundles: [NSBundle]?, completion: (NSPersistentStore) -> Void, failure: (NSError) -> Void) throws {
coordinator.performBlock {
do {
let persistentStore = try coordinator.addPersistentStoreWithType(
self.dynamicType.storeType,
configuration: self.configuration,
URL: self.storeURL,
options: self.storeOptions
)
completion(persistentStore)
}
catch {
failure(error as NSError)
}
}
}
}

View File

@@ -0,0 +1,90 @@
//
// LegacySQLiteStore.swift
// CoreStore
//
// Copyright © 2016 John Rommel Estropia
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
import Foundation
// MARK: - LegacySQLiteStore
public final class LegacySQLiteStore: SQLiteStore {
public required init(fileURL: NSURL, configuration: String? = nil, resetStoreOnModelMismatch: Bool = false) {
super.init(
fileURL: fileURL,
configuration: configuration,
resetStoreOnModelMismatch: resetStoreOnModelMismatch
)
}
/**
Initializes an SQLite store interface from the given SQLite file name. When this instance is passed to the `DataStack`'s `addStorage()` methods, a new SQLite file will be created if it does not exist.
- parameter fileName: the local filename for the SQLite persistent store in the "Application Support/<bundle id>" directory (or the "Caches/<bundle id>" directory on tvOS). Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
- parameter configuration: an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration. Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
- parameter resetStoreOnModelMismatch: When the `SQLiteStore` is passed to the `DataStack`'s `addStorage()` methods, a true value tells the `DataStack` to delete the store on model mismatch; a false value lets exceptions be thrown on failure instead. Typically should only be set to true when debugging, or if the persistent store can be recreated easily. If not specified, defaults to false.
*/
public required init(fileName: String, configuration: String? = nil, resetStoreOnModelMismatch: Bool = false) {
super.init(
fileURL: LegacySQLiteStore.legacyDefaultRootDirectory.URLByAppendingPathComponent(
fileName,
isDirectory: false
),
configuration: configuration,
resetStoreOnModelMismatch: resetStoreOnModelMismatch
)
}
// MARK: DefaultInitializableStore
public required init() {
super.init(
fileURL: LegacySQLiteStore.legacyDefaultFileURL,
configuration: nil,
resetStoreOnModelMismatch: false
)
}
// MARK: Internal
#if os(tvOS)
internal static let systemDirectorySearchPath = NSSearchPathDirectory.CachesDirectory
#else
internal static let systemDirectorySearchPath = NSSearchPathDirectory.ApplicationSupportDirectory
#endif
internal static let legacyDefaultRootDirectory = NSFileManager.defaultManager().URLsForDirectory(
LegacySQLiteStore.systemDirectorySearchPath,
inDomains: .UserDomainMask
).first!
internal static let legacyDefaultFileURL = LegacySQLiteStore.legacyDefaultRootDirectory
.URLByAppendingPathComponent(DataStack.applicationName, isDirectory: false)
.URLByAppendingPathExtension("sqlite")
}

View File

@@ -30,33 +30,6 @@ import CoreData
public class SQLiteStore: StorageInterface, DefaultInitializableStore {
public static let defaultRootDirectory: NSURL = {
#if os(tvOS)
let systemDirectorySearchPath = NSSearchPathDirectory.CachesDirectory
#else
let systemDirectorySearchPath = NSSearchPathDirectory.ApplicationSupportDirectory
#endif
let defaultSystemDirectory = NSFileManager
.defaultManager()
.URLsForDirectory(systemDirectorySearchPath, inDomains: .UserDomainMask).first!
return defaultSystemDirectory.URLByAppendingPathComponent(
NSBundle.mainBundle().bundleIdentifier ?? "com.CoreStore.DataStack",
isDirectory: true
)
}()
public static let defaultFileURL: NSURL = {
let applicationName = (NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleName") as? String) ?? "CoreData"
return SQLiteStore.defaultRootDirectory
.URLByAppendingPathComponent(applicationName, isDirectory: false)
.URLByAppendingPathExtension("sqlite")
}()
/**
Initializes an SQLite store interface from the given SQLite file URL. When this instance is passed to the `DataStack`'s `addStorage()` methods, a new SQLite file will be created if it does not exist.
@@ -101,13 +74,17 @@ public class SQLiteStore: StorageInterface, DefaultInitializableStore {
public static let storeType = NSSQLiteStoreType
public static func validateStoreURL(storeURL: NSURL?) -> Bool {
return storeURL?.fileURL == true
}
public var storeURL: NSURL? {
return self.fileURL
}
public let configuration: String?
public let storeOptions: [String: AnyObject]? = [NSSQLitePragmasOption: ["journal_mode": "WAL"]]
public var internalStore: NSPersistentStore?
@@ -144,9 +121,133 @@ public class SQLiteStore: StorageInterface, DefaultInitializableStore {
}
}
public func addToPersistentStoreCoordinatorAsynchronously(coordinator: NSPersistentStoreCoordinator, mappingModelBundles: [NSBundle]?, completion: (NSPersistentStore) -> Void, failure: (NSError) -> Void) throws {
let fileManager = NSFileManager.defaultManager()
do {
let fileURL = self.fileURL
try fileManager.createDirectoryAtURL(
fileURL.URLByDeletingLastPathComponent!,
withIntermediateDirectories: true,
attributes: nil
)
let metadata = try NSPersistentStoreCoordinator.metadataForPersistentStoreOfType(
self.dynamicType.storeType,
URL: fileURL,
options: self.storeOptions
)
return self.upgradeSQLiteStoreIfNeeded(
fileURL: fileURL,
metadata: metadata,
configuration: configuration,
mappingModelBundles: mappingModelBundles,
completion: { (result) -> Void in
if case .Failure(let error) = result {
if resetStoreOnModelMismatch && error.isCoreDataMigrationError {
fileManager.removeSQLiteStoreAtURL(fileURL)
do {
let store = try self.addSQLiteStoreAndWait(
fileURL: fileURL,
configuration: configuration,
resetStoreOnModelMismatch: false
)
GCDQueue.Main.async {
completion(PersistentStoreResult(store))
}
}
catch {
completion(PersistentStoreResult(error as NSError))
}
return
}
completion(PersistentStoreResult(error))
return
}
do {
let store = try self.addSQLiteStoreAndWait(
fileURL: fileURL,
configuration: configuration,
resetStoreOnModelMismatch: false
)
completion(PersistentStoreResult(store))
}
catch {
completion(PersistentStoreResult(error as NSError))
}
}
)
}
catch let error as NSError
where error.code == NSFileReadNoSuchFileError && error.domain == NSCocoaErrorDomain {
let store = try self.addSQLiteStoreAndWait(
fileURL: fileURL,
configuration: configuration,
resetStoreOnModelMismatch: false
)
GCDQueue.Main.async {
completion(PersistentStoreResult(store))
}
return nil
}
catch {
CoreStore.handleError(
error as NSError,
"Failed to load SQLite \(typeName(NSPersistentStore)) metadata."
)
throw error
}
}
// MARK: Internal
internal static let defaultRootDirectory: NSURL = {
#if os(tvOS)
let systemDirectorySearchPath = NSSearchPathDirectory.CachesDirectory
#else
let systemDirectorySearchPath = NSSearchPathDirectory.ApplicationSupportDirectory
#endif
let defaultSystemDirectory = NSFileManager
.defaultManager()
.URLsForDirectory(systemDirectorySearchPath, inDomains: .UserDomainMask).first!
return defaultSystemDirectory.URLByAppendingPathComponent(
NSBundle.mainBundle().bundleIdentifier ?? "com.CoreStore.DataStack",
isDirectory: true
)
}()
internal static let defaultFileURL: NSURL = {
let applicationName = (NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleName") as? String) ?? "CoreData"
return SQLiteStore.defaultRootDirectory
.URLByAppendingPathComponent(applicationName, isDirectory: false)
.URLByAppendingPathExtension("sqlite")
}()
internal let fileURL: NSURL
internal let resetStoreOnModelMismatch: Bool

View File

@@ -31,52 +31,17 @@ import CoreData
public protocol StorageInterface: class {
static var storeType: String { get }
static func validateStoreURL(storeURL: NSURL?) -> Bool
var storeURL: NSURL? { get }
var configuration: String? { get }
var storeOptions: [String: AnyObject]? { get }
var internalStore: NSPersistentStore? { get set }
func addToPersistentStoreCoordinatorSynchronously(coordinator: NSPersistentStoreCoordinator) throws -> NSPersistentStore
func addToPersistentStoreCoordinatorAsynchronously(coordinator: NSPersistentStoreCoordinator, completion: (NSPersistentStore) -> Void, failure: (NSError) -> Void) throws
}
public extension StorageInterface {
public func addToPersistentStoreCoordinatorSynchronously(coordinator: NSPersistentStoreCoordinator) throws -> NSPersistentStore {
return try coordinator.addPersistentStoreSynchronously(
self.dynamicType.storeType,
configuration: self.configuration,
URL: self.storeURL,
options: self.storeOptions
)
}
public func addToPersistentStoreCoordinatorAsynchronously(coordinator: NSPersistentStoreCoordinator, completion: (NSPersistentStore) -> Void, failure: (NSError) -> Void) throws {
coordinator.performBlock {
do {
let persistentStore = try coordinator.addPersistentStoreWithType(
self.dynamicType.storeType,
configuration: self.configuration,
URL: self.storeURL,
options: self.storeOptions
)
completion(persistentStore)
}
catch {
failure(error as NSError)
}
}
}
func addToPersistentStoreCoordinatorAsynchronously(coordinator: NSPersistentStoreCoordinator, mappingModelBundles: [NSBundle]?, completion: (NSPersistentStore) -> Void, failure: (NSError) -> Void) throws
}