mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-01-12 20:30:30 +01:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0048f589c | ||
|
|
929fdfd9a9 | ||
|
|
c1967ecdd3 | ||
|
|
1a56dfd708 | ||
|
|
3bbae948ca | ||
|
|
d247198093 | ||
|
|
589e5618ce | ||
|
|
8402ebcc0f | ||
|
|
caf5c570df | ||
|
|
71c80c3497 | ||
|
|
832dd8826e | ||
|
|
fcda83e6ac | ||
|
|
7303e05820 | ||
|
|
a44400a935 | ||
|
|
f18d29d9bc |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
HardcoreData.xcodeproj/xcuserdata
|
||||
HardcoreDataDemo/HardcoreDataDemo.xcodeproj/xcuserdata
|
||||
HardcoreDataDemo/HardcoreDataDemo.xcodeproj/project.xcworkspace/xcuserdata
|
||||
CoreStoreDemo/CoreStoreDemo.xcodeproj/project.xcworkspace/xcuserdata
|
||||
CoreStore.xcodeproj/project.xcworkspace/xcuserdata
|
||||
CoreStore.xcodeproj/xcuserdata
|
||||
CoreStoreDemo/CoreStoreDemo.xcodeproj/xcuserdata
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = "CoreStore"
|
||||
s.version = "0.1.2"
|
||||
s.version = "0.2.1"
|
||||
s.license = "MIT"
|
||||
s.summary = "Simple, elegant, and smart Core Data programming with Swift"
|
||||
s.homepage = "https://github.com/JohnEstropia/CoreStore"
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
2F03A54D19C5C872005002A5 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2F03A54C19C5C872005002A5 /* CoreData.framework */; };
|
||||
2F291E2719C6D3CF007AF63F /* CoreStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F291E2619C6D3CF007AF63F /* CoreStore.swift */; };
|
||||
B504D0D61B02362500B2BBB1 /* CoreStore+Setup.swift in Sources */ = {isa = PBXBuildFile; fileRef = B504D0D51B02362500B2BBB1 /* CoreStore+Setup.swift */; };
|
||||
B56964D41B22FFAD0075EE4A /* DataStack+Migration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56964D31B22FFAD0075EE4A /* DataStack+Migration.swift */; };
|
||||
B5D1E22C19FA9FBC003B2874 /* NSError+CoreStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D1E22B19FA9FBC003B2874 /* NSError+CoreStore.swift */; };
|
||||
B5D372841A39CD6900F583D9 /* Model.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B5D372821A39CD6900F583D9 /* Model.xcdatamodeld */; };
|
||||
B5D372861A39CDDB00F583D9 /* TestEntity1.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5D372851A39CDDB00F583D9 /* TestEntity1.swift */; };
|
||||
@@ -99,6 +100,7 @@
|
||||
2F03A54C19C5C872005002A5 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
|
||||
2F291E2619C6D3CF007AF63F /* CoreStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = CoreStore.swift; sourceTree = "<group>"; };
|
||||
B504D0D51B02362500B2BBB1 /* CoreStore+Setup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CoreStore+Setup.swift"; sourceTree = "<group>"; };
|
||||
B56964D31B22FFAD0075EE4A /* DataStack+Migration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DataStack+Migration.swift"; sourceTree = "<group>"; };
|
||||
B5D1E22B19FA9FBC003B2874 /* NSError+CoreStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSError+CoreStore.swift"; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
@@ -201,6 +203,7 @@
|
||||
B5E84EE91AFF846E0064E85B /* Saving and Processing */,
|
||||
B5E84EFD1AFF847B0064E85B /* Fetching and Querying */,
|
||||
B5E84F191AFF84860064E85B /* Observing */,
|
||||
B56964D11B22FF700075EE4A /* Migrating */,
|
||||
B5E84F261AFF84920064E85B /* Convenience Helpers */,
|
||||
B5E84F291AFF849C0064E85B /* Internal */,
|
||||
2F03A53319C5C6DA005002A5 /* Supporting Files */,
|
||||
@@ -249,6 +252,14 @@
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B56964D11B22FF700075EE4A /* Migrating */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B56964D31B22FFAD0075EE4A /* DataStack+Migration.swift */,
|
||||
);
|
||||
path = Migrating;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5D806BB1A34715700A44484 /* Libraries */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -531,6 +542,7 @@
|
||||
B5E84EDF1AFF84500064E85B /* DataStack.swift in Sources */,
|
||||
B5E84F231AFF84860064E85B /* ManagedObjectListController.swift in Sources */,
|
||||
B5E84EF71AFF846E0064E85B /* DetachedDataTransaction.swift in Sources */,
|
||||
B56964D41B22FFAD0075EE4A /* DataStack+Migration.swift in Sources */,
|
||||
B5E84EF51AFF846E0064E85B /* BaseDataTransaction.swift in Sources */,
|
||||
B5E84EFB1AFF846E0064E85B /* SaveResult.swift in Sources */,
|
||||
B5E84F0F1AFF847B0064E85B /* From.swift in Sources */,
|
||||
@@ -674,10 +686,6 @@
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/PhotoSearch-dzwflhandxxuvngptapvysfpcwdx/Build/Products/Debug-iphoneos",
|
||||
);
|
||||
INFOPLIST_FILE = CoreStore/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
@@ -686,6 +694,7 @@
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_WHOLE_MODULE_OPTIMIZATION = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
@@ -698,10 +707,6 @@
|
||||
DYLIB_CURRENT_VERSION = 1;
|
||||
DYLIB_INSTALL_NAME_BASE = "@rpath";
|
||||
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(USER_LIBRARY_DIR)/Developer/Xcode/DerivedData/PhotoSearch-dzwflhandxxuvngptapvysfpcwdx/Build/Products/Debug-iphoneos",
|
||||
);
|
||||
INFOPLIST_FILE = CoreStore/Info.plist;
|
||||
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
@@ -709,6 +714,7 @@
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
SWIFT_WHOLE_MODULE_OPTIMIZATION = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>SchemeUserState</key>
|
||||
<dict>
|
||||
<key>CoreStore.xcscheme</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
<dict>
|
||||
<key>2F03A52F19C5C6DA005002A5</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>2F03A53A19C5C6DA005002A5</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.1.2</string>
|
||||
<string>0.2.1</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
357
CoreStore/Migrating/DataStack+Migration.swift
Normal file
357
CoreStore/Migrating/DataStack+Migration.swift
Normal file
@@ -0,0 +1,357 @@
|
||||
//
|
||||
// DataStack+Migration.swift
|
||||
// CoreStore
|
||||
//
|
||||
// Copyright (c) 2015 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
|
||||
import CoreData
|
||||
import GCDKit
|
||||
|
||||
|
||||
// MARK: - DataStack
|
||||
|
||||
public extension DataStack {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
/**
|
||||
Initializes a `DataStack` from the specified model name and a version-specific model name.
|
||||
|
||||
:param: rootModelName the name of the (.xcdatamodeld) model file
|
||||
:param: versionModelName the name of the version-specific (.xcdatamodeld) model file
|
||||
*/
|
||||
public convenience init(rootModelName: String, versionModelName: String) {
|
||||
|
||||
let modelVersionURL: NSURL! = NSBundle.mainBundle().URLForResource(
|
||||
rootModelName.stringByAppendingPathExtension("momd")!.stringByAppendingPathComponent(versionModelName),
|
||||
withExtension: "mom"
|
||||
)
|
||||
CoreStore.assert(modelVersionURL != nil, "Could not find a \"mom\" resource from the main bundle.")
|
||||
|
||||
let managedObjectModel: NSManagedObjectModel! = NSManagedObjectModel(contentsOfURL: modelVersionURL)
|
||||
CoreStore.assert(managedObjectModel != nil, "Could not create an <\(NSManagedObjectModel.self)> from the resource at URL \"\(modelVersionURL)\".")
|
||||
|
||||
self.init(managedObjectModel: managedObjectModel)
|
||||
}
|
||||
|
||||
/**
|
||||
Checks if the store at the specified filename and configuration needs to be migrated to the `DataStack`'s managed object model version.
|
||||
|
||||
:param: fileName the local filename for the SQLite persistent store in the "Application Support" directory.
|
||||
:param: configuration an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration.
|
||||
*/
|
||||
public func needsMigrationForSQLiteStore(fileName: String, configuration: String? = nil) -> Bool? {
|
||||
|
||||
return needsMigrationForSQLiteStore(
|
||||
fileURL: applicationSupportDirectory.URLByAppendingPathComponent(
|
||||
fileName,
|
||||
isDirectory: false
|
||||
),
|
||||
configuration: configuration
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Checks if the store at the specified file URL and configuration needs to be migrated to the `DataStack`'s managed object model version.
|
||||
|
||||
:param: fileName the local filename for the SQLite persistent store in the "Application Support" directory.
|
||||
:param: configuration an optional configuration name from the model file. If not specified, defaults to `nil`, the "Default" configuration.
|
||||
*/
|
||||
public func needsMigrationForSQLiteStore(fileURL: NSURL = defaultSQLiteStoreURL, configuration: String? = nil) -> Bool? {
|
||||
|
||||
var error: NSError?
|
||||
let metadata = NSPersistentStoreCoordinator.metadataForPersistentStoreOfType(
|
||||
NSSQLiteStoreType,
|
||||
URL: fileURL,
|
||||
error: &error
|
||||
)
|
||||
if metadata == nil {
|
||||
|
||||
CoreStore.handleError(
|
||||
error ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed to add SQLite <\(NSPersistentStore.self)> at \"\(fileURL)\".")
|
||||
return nil
|
||||
}
|
||||
|
||||
return !self.coordinator.managedObjectModel.isConfiguration(
|
||||
configuration,
|
||||
compatibleWithStoreMetadata: metadata
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
EXPERIMENTAL
|
||||
*/
|
||||
private func upgradeSQLiteStoreIfNeeded(fileName: String, configuration: String? = nil, completion: (PersistentStoreResult) -> Void) {
|
||||
|
||||
self.upgradeSQLiteStoreIfNeeded(
|
||||
fileURL: applicationSupportDirectory.URLByAppendingPathComponent(
|
||||
fileName,
|
||||
isDirectory: false
|
||||
),
|
||||
configuration: configuration,
|
||||
completion: completion
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
EXPERIMENTAL
|
||||
*/
|
||||
private func upgradeSQLiteStoreIfNeeded(fileURL: NSURL = defaultSQLiteStoreURL, configuration: String? = nil, completion: (PersistentStoreResult) -> Void) {
|
||||
|
||||
var metadataError: NSError?
|
||||
let metadata: [NSObject: AnyObject]! = NSPersistentStoreCoordinator.metadataForPersistentStoreOfType(
|
||||
NSSQLiteStoreType,
|
||||
URL: fileURL,
|
||||
error: &metadataError
|
||||
)
|
||||
if metadata == nil {
|
||||
|
||||
CoreStore.handleError(
|
||||
metadataError ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed to load SQLite <\(NSPersistentStore.self)> metadata at \"\(fileURL)\".")
|
||||
|
||||
GCDQueue.Main.async {
|
||||
|
||||
// TODO: inspect valid errors for metadataForPersistentStoreOfType()
|
||||
completion(PersistentStoreResult(.PersistentStoreNotFound))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
let coordinator = self.coordinator;
|
||||
if let store = coordinator.persistentStoreForURL(fileURL) {
|
||||
|
||||
let isExistingStoreAutomigrating = ((store.options?[NSMigratePersistentStoresAutomaticallyOption] as? Bool) ?? false)
|
||||
|
||||
if store.type == NSSQLiteStoreType
|
||||
&& isExistingStoreAutomigrating
|
||||
&& store.configurationName == (configuration ?? Into.defaultConfigurationName) {
|
||||
|
||||
GCDQueue.Main.async {
|
||||
|
||||
completion(PersistentStoreResult(store))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
CoreStore.handleError(
|
||||
NSError(coreStoreErrorCode: .DifferentPersistentStoreExistsAtURL),
|
||||
"Failed to add SQLite <\(NSPersistentStore.self)> at \"\(fileURL)\" because a different <\(NSPersistentStore.self)> at that URL already exists.")
|
||||
|
||||
GCDQueue.Main.async {
|
||||
|
||||
completion(PersistentStoreResult(.DifferentPersistentStoreExistsAtURL))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
let managedObjectModel = self.coordinator.managedObjectModel
|
||||
let migrationManager = NSMigrationManager(
|
||||
sourceModel: NSManagedObjectModel(
|
||||
byMergingModels: [managedObjectModel],
|
||||
forStoreMetadata: metadata!
|
||||
)!,
|
||||
destinationModel: managedObjectModel
|
||||
)
|
||||
|
||||
var mappingModel: NSMappingModel! = NSMappingModel(
|
||||
fromBundles: nil, // TODO: parametize
|
||||
forSourceModel: migrationManager.sourceModel,
|
||||
destinationModel: migrationManager.destinationModel
|
||||
)
|
||||
var modelError: NSError?
|
||||
if mappingModel == nil {
|
||||
|
||||
mappingModel = NSMappingModel.inferredMappingModelForSourceModel(
|
||||
migrationManager.sourceModel,
|
||||
destinationModel: migrationManager.destinationModel,
|
||||
error: &modelError
|
||||
)
|
||||
}
|
||||
if mappingModel == nil {
|
||||
|
||||
CoreStore.handleError(
|
||||
NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed to load an <\(NSMappingModel.self)> for migration from version model \"\(migrationManager.sourceModel)\" to version model \"\(migrationManager.destinationModel)\".")
|
||||
|
||||
GCDQueue.Main.async {
|
||||
|
||||
completion(PersistentStoreResult(.MappingModelNotFound))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
let temporaryFileURL = NSURL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)!.URLByAppendingPathComponent(NSProcessInfo().globallyUniqueString)
|
||||
|
||||
var migrationError: NSError?
|
||||
if !migrationManager.migrateStoreFromURL(
|
||||
fileURL,
|
||||
type: NSSQLiteStoreType,
|
||||
options: nil,
|
||||
withMappingModel: mappingModel,
|
||||
toDestinationURL: temporaryFileURL,
|
||||
destinationType: NSSQLiteStoreType,
|
||||
destinationOptions: nil,
|
||||
error: &migrationError
|
||||
) {
|
||||
|
||||
CoreStore.handleError(
|
||||
migrationError ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed to prepare for migration from version model \"\(migrationManager.sourceModel)\" to version model \"\(migrationManager.destinationModel)\".")
|
||||
|
||||
GCDQueue.Main.async {
|
||||
|
||||
completion(PersistentStoreResult(.MigrationFailed))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Asynchronously adds to the stack an SQLite store from the given SQLite file name. Note that using `addSQLiteStore(...)` instead of `addSQLiteStoreAndWait(...)` implies that the migrations are allowed and expected (thus the asynchronous `completion`.)
|
||||
|
||||
:param: fileName the local filename for the SQLite persistent store in the "Application Support" directory. A new SQLite file will be created if it does not exist. Note that if you have multiple configurations, you will need to specify a different `fileName` explicitly for each of them.
|
||||
:param: 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.
|
||||
:param: completion the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `PersistentStoreResult` argument indicates the result.
|
||||
*/
|
||||
public func addSQLiteStore(fileName: String, configuration: String? = nil, completion: (PersistentStoreResult) -> Void) {
|
||||
|
||||
self.addSQLiteStore(
|
||||
fileURL: applicationSupportDirectory.URLByAppendingPathComponent(
|
||||
fileName,
|
||||
isDirectory: false
|
||||
),
|
||||
configuration: configuration,
|
||||
completion: completion
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Asynchronously adds to the stack an SQLite store from the given SQLite file URL. Note that using `addSQLiteStore(...)` instead of `addSQLiteStoreAndWait(...)` implies that the migrations are allowed and expected (thus the asynchronous `completion`.)
|
||||
|
||||
:param: fileURL the local file URL for the SQLite persistent store. A new SQLite file will be created if it does not exist. If not specified, defaults to a file URL pointing to a "<Application name>.sqlite" file in the "Application Support" directory. Note that if you have multiple configurations, you will need to specify a different `fileURL` explicitly for each of them.
|
||||
:param: 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 `fileURL` explicitly for each of them.
|
||||
:param: completion the closure to be executed on the main queue when the process completes, either due to success or failure. The closure's `PersistentStoreResult` argument indicates the result.
|
||||
*/
|
||||
public func addSQLiteStore(fileURL: NSURL = defaultSQLiteStoreURL, configuration: String? = nil, completion: (PersistentStoreResult) -> Void) {
|
||||
|
||||
var error: NSError?
|
||||
let metadata = NSPersistentStoreCoordinator.metadataForPersistentStoreOfType(
|
||||
NSSQLiteStoreType,
|
||||
URL: fileURL,
|
||||
error: &error
|
||||
)
|
||||
if metadata == nil {
|
||||
|
||||
CoreStore.handleError(
|
||||
error ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed to load SQLite <\(NSPersistentStore.self)> metadata at \"\(fileURL)\".")
|
||||
|
||||
GCDQueue.Main.async {
|
||||
|
||||
completion(PersistentStoreResult(.UnknownError))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
let coordinator = self.coordinator;
|
||||
if let store = coordinator.persistentStoreForURL(fileURL) {
|
||||
|
||||
let isExistingStoreAutomigrating = ((store.options?[NSMigratePersistentStoresAutomaticallyOption] as? Bool) ?? false)
|
||||
|
||||
if store.type == NSSQLiteStoreType
|
||||
&& isExistingStoreAutomigrating
|
||||
&& store.configurationName == (configuration ?? Into.defaultConfigurationName) {
|
||||
|
||||
GCDQueue.Main.async {
|
||||
|
||||
completion(PersistentStoreResult(store))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
CoreStore.handleError(
|
||||
NSError(coreStoreErrorCode: .DifferentPersistentStoreExistsAtURL),
|
||||
"Failed to add SQLite <\(NSPersistentStore.self)> at \"\(fileURL)\" because a different <\(NSPersistentStore.self)> at that URL already exists.")
|
||||
|
||||
GCDQueue.Main.async {
|
||||
|
||||
completion(PersistentStoreResult(.DifferentPersistentStoreExistsAtURL))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
let fileManager = NSFileManager.defaultManager()
|
||||
var directoryError: NSError?
|
||||
if !fileManager.createDirectoryAtURL(
|
||||
fileURL.URLByDeletingLastPathComponent!,
|
||||
withIntermediateDirectories: true,
|
||||
attributes: nil,
|
||||
error: &directoryError) {
|
||||
|
||||
CoreStore.handleError(
|
||||
directoryError ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed to create directory for SQLite store at \"\(fileURL)\".")
|
||||
GCDQueue.Main.async {
|
||||
|
||||
completion(PersistentStoreResult(directoryError!))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
coordinator.performBlock {
|
||||
|
||||
var persistentStoreError: NSError?
|
||||
let store = coordinator.addPersistentStoreWithType(
|
||||
NSSQLiteStoreType,
|
||||
configuration: configuration,
|
||||
URL: fileURL,
|
||||
options: [NSSQLitePragmasOption: ["WAL": "journal_mode"],
|
||||
NSInferMappingModelAutomaticallyOption: true,
|
||||
NSMigratePersistentStoresAutomaticallyOption: true],
|
||||
error: &persistentStoreError)
|
||||
|
||||
if let store = store {
|
||||
|
||||
GCDQueue.Main.async {
|
||||
|
||||
self.updateMetadataForPersistentStore(store)
|
||||
completion(PersistentStoreResult(store))
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
GCDQueue.Main.async {
|
||||
|
||||
CoreStore.handleError(
|
||||
persistentStoreError ?? NSError(coreStoreErrorCode: .UnknownError),
|
||||
"Failed to add SQLite <\(NSPersistentStore.self)> at \"\(fileURL)\".")
|
||||
|
||||
completion(PersistentStoreResult(.UnknownError))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,21 @@ public enum CoreStoreErrorCode: Int {
|
||||
The `NSPersistentStore` could note be initialized because another store existed at the specified `NSURL`.
|
||||
*/
|
||||
case DifferentPersistentStoreExistsAtURL
|
||||
|
||||
/**
|
||||
The `NSPersistentStore` specified could not be found.
|
||||
*/
|
||||
case PersistentStoreNotFound
|
||||
|
||||
/**
|
||||
An `NSMappingModel` could not be found for a specific source and destination model versions.
|
||||
*/
|
||||
case MappingModelNotFound
|
||||
|
||||
/**
|
||||
An `NSMigrationManager` prepared to migrate the store.
|
||||
*/
|
||||
case MigrationFailed
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -41,8 +41,6 @@ public extension DataStack {
|
||||
*/
|
||||
public func beginAsynchronous(closure: (transaction: AsynchronousDataTransaction) -> Void) {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to begin a transaction from a \(typeName(self)) outside the main thread.")
|
||||
|
||||
AsynchronousDataTransaction(
|
||||
mainContext: self.rootSavingContext,
|
||||
queue: self.childTransactionQueue,
|
||||
@@ -57,8 +55,6 @@ public extension DataStack {
|
||||
*/
|
||||
public func beginSynchronous(closure: (transaction: SynchronousDataTransaction) -> Void) -> SaveResult? {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to begin a transaction from a \(typeName(self)) outside the main thread.")
|
||||
|
||||
return SynchronousDataTransaction(
|
||||
mainContext: self.rootSavingContext,
|
||||
queue: self.childTransactionQueue,
|
||||
@@ -72,8 +68,6 @@ public extension DataStack {
|
||||
*/
|
||||
public func beginDetached() -> DetachedDataTransaction {
|
||||
|
||||
CoreStore.assert(NSThread.isMainThread(), "Attempted to begin a transaction from a \(typeName(self)) outside the main thread.")
|
||||
|
||||
return DetachedDataTransaction(
|
||||
mainContext: self.rootSavingContext,
|
||||
queue: .Main)
|
||||
|
||||
@@ -52,9 +52,9 @@ public extension CoreStore {
|
||||
:param: resetStoreOnMigrationFailure Set to true to delete the store on migration failure; or set to false to throw exceptions 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
|
||||
:returns: a `PersistentStoreResult` indicating success or failure.
|
||||
*/
|
||||
public static func addSQLiteStore(fileName: String, configuration: String? = nil, automigrating: Bool = true, resetStoreOnMigrationFailure: Bool = false) -> PersistentStoreResult {
|
||||
public static func addSQLiteStoreAndWait(fileName: String, configuration: String? = nil, automigrating: Bool = true, resetStoreOnMigrationFailure: Bool = false) -> PersistentStoreResult {
|
||||
|
||||
return self.defaultStack.addSQLiteStore(
|
||||
return self.defaultStack.addSQLiteStoreAndWait(
|
||||
fileName,
|
||||
configuration: configuration,
|
||||
automigrating: automigrating,
|
||||
@@ -71,9 +71,9 @@ public extension CoreStore {
|
||||
:param: resetStoreOnMigrationFailure Set to true to delete the store on migration failure; or set to false to throw exceptions 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.
|
||||
:returns: a `PersistentStoreResult` indicating success or failure.
|
||||
*/
|
||||
public static func addSQLiteStore(fileURL: NSURL = defaultSQLiteStoreURL, configuration: String? = nil, automigrating: Bool = true, resetStoreOnMigrationFailure: Bool = false) -> PersistentStoreResult {
|
||||
public static func addSQLiteStoreAndWait(fileURL: NSURL = defaultSQLiteStoreURL, configuration: String? = nil, automigrating: Bool = true, resetStoreOnMigrationFailure: Bool = false) -> PersistentStoreResult {
|
||||
|
||||
return self.defaultStack.addSQLiteStore(
|
||||
return self.defaultStack.addSQLiteStoreAndWait(
|
||||
fileURL: fileURL,
|
||||
configuration: configuration,
|
||||
automigrating: automigrating,
|
||||
|
||||
@@ -28,9 +28,9 @@ import CoreData
|
||||
import GCDKit
|
||||
|
||||
|
||||
private let applicationSupportDirectory = NSFileManager.defaultManager().URLsForDirectory(.ApplicationSupportDirectory, inDomains: .UserDomainMask).first as! NSURL
|
||||
internal let applicationSupportDirectory = NSFileManager.defaultManager().URLsForDirectory(.ApplicationSupportDirectory, inDomains: .UserDomainMask).first as! NSURL
|
||||
|
||||
private let applicationName = ((NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleName") as? String) ?? "CoreData")
|
||||
internal let applicationName = ((NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleName") as? String) ?? "CoreData")
|
||||
|
||||
internal let defaultSQLiteStoreURL = applicationSupportDirectory.URLByAppendingPathComponent(applicationName, isDirectory: false).URLByAppendingPathExtension("sqlite")
|
||||
|
||||
@@ -152,9 +152,9 @@ public final class DataStack {
|
||||
:param: resetStoreOnMigrationFailure Set to true to delete the store on migration failure; or set to false to throw exceptions 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
|
||||
:returns: a `PersistentStoreResult` indicating success or failure.
|
||||
*/
|
||||
public func addSQLiteStore(fileName: String, configuration: String? = nil, automigrating: Bool = true, resetStoreOnMigrationFailure: Bool = false) -> PersistentStoreResult {
|
||||
public func addSQLiteStoreAndWait(fileName: String, configuration: String? = nil, automigrating: Bool = true, resetStoreOnMigrationFailure: Bool = false) -> PersistentStoreResult {
|
||||
|
||||
return self.addSQLiteStore(
|
||||
return self.addSQLiteStoreAndWait(
|
||||
fileURL: applicationSupportDirectory.URLByAppendingPathComponent(
|
||||
fileName,
|
||||
isDirectory: false
|
||||
@@ -174,7 +174,7 @@ public final class DataStack {
|
||||
:param: resetStoreOnMigrationFailure Set to true to delete the store on migration failure; or set to false to throw exceptions 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.
|
||||
:returns: a `PersistentStoreResult` indicating success or failure.
|
||||
*/
|
||||
public func addSQLiteStore(fileURL: NSURL = defaultSQLiteStoreURL, configuration: String? = nil, automigrating: Bool = true, resetStoreOnMigrationFailure: Bool = false) -> PersistentStoreResult {
|
||||
public func addSQLiteStoreAndWait(fileURL: NSURL = defaultSQLiteStoreURL, configuration: String? = nil, automigrating: Bool = true, resetStoreOnMigrationFailure: Bool = false) -> PersistentStoreResult {
|
||||
|
||||
let coordinator = self.coordinator;
|
||||
if let store = coordinator.persistentStoreForURL(fileURL) {
|
||||
@@ -276,6 +276,7 @@ public final class DataStack {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal let coordinator: NSPersistentStoreCoordinator
|
||||
internal let rootSavingContext: NSManagedObjectContext
|
||||
internal let mainContext: NSManagedObjectContext
|
||||
internal let childTransactionQueue: GCDQueue = .createSerial("com.corestore.datastack.childtransactionqueue")
|
||||
@@ -333,20 +334,7 @@ public final class DataStack {
|
||||
return returnValue
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private typealias EntityClassNameType = String
|
||||
private typealias EntityNameType = String
|
||||
private typealias ConfigurationNameType = String
|
||||
|
||||
private let coordinator: NSPersistentStoreCoordinator
|
||||
private let entityNameMapping: [EntityClassNameType: EntityNameType]
|
||||
private let storeMetadataUpdateQueue = GCDQueue.createConcurrent("com.coreStore.persistentStoreBarrierQueue")
|
||||
private var configurationStoreMapping = [ConfigurationNameType: NSPersistentStore]()
|
||||
private var entityConfigurationsMapping = [EntityClassNameType: Set<String>]()
|
||||
|
||||
private func updateMetadataForPersistentStore(persistentStore: NSPersistentStore) {
|
||||
internal func updateMetadataForPersistentStore(persistentStore: NSPersistentStore) {
|
||||
|
||||
self.storeMetadataUpdateQueue.barrierAsync {
|
||||
|
||||
@@ -358,4 +346,16 @@ public final class DataStack {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private typealias EntityClassNameType = String
|
||||
private typealias EntityNameType = String
|
||||
private typealias ConfigurationNameType = String
|
||||
|
||||
private let entityNameMapping: [EntityClassNameType: EntityNameType]
|
||||
private let storeMetadataUpdateQueue = GCDQueue.createConcurrent("com.coreStore.persistentStoreBarrierQueue")
|
||||
private var configurationStoreMapping = [ConfigurationNameType: NSPersistentStore]()
|
||||
private var entityConfigurationsMapping = [EntityClassNameType: Set<String>]()
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ import CoreData
|
||||
The `PersistentStoreResult` indicates the result of initializing the persistent store.
|
||||
The `PersistentStoreResult` can be treated as a boolean:
|
||||
|
||||
let result = CoreStore.addSQLiteStore()
|
||||
let result = CoreStore.addSQLiteStoreAndWait()
|
||||
if result {
|
||||
// succeeded
|
||||
}
|
||||
@@ -43,7 +43,7 @@ The `PersistentStoreResult` can be treated as a boolean:
|
||||
|
||||
or as an `enum`, where the resulting associated object can also be inspected:
|
||||
|
||||
let result = CoreStore.addSQLiteStore()
|
||||
let result = CoreStore.addSQLiteStoreAndWait()
|
||||
switch result {
|
||||
case .Success(let persistentStore):
|
||||
// persistentStore is the related NSPersistentStore instance
|
||||
|
||||
@@ -24,12 +24,18 @@
|
||||
B566E32A1B117B1F00F4F0C6 /* StackSetupDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B566E3291B117B1F00F4F0C6 /* StackSetupDemoViewController.swift */; };
|
||||
B566E3321B11DF3200F4F0C6 /* UserAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = B566E3311B11DF3200F4F0C6 /* UserAccount.swift */; };
|
||||
B56964C91B20AC780075EE4A /* CustomLoggerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56964C81B20AC780075EE4A /* CustomLoggerViewController.swift */; };
|
||||
B56964D71B231AE90075EE4A /* StackSetupDemo.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B56964D51B231AE90075EE4A /* StackSetupDemo.xcdatamodeld */; };
|
||||
B56964DA1B231BCA0075EE4A /* MaleAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56964D91B231BCA0075EE4A /* MaleAccount.swift */; };
|
||||
B56964DC1B231BCB0075EE4A /* FemaleAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56964DB1B231BCB0075EE4A /* FemaleAccount.swift */; };
|
||||
B56964DF1B2321E30075EE4A /* MigrationDemo.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B56964DD1B2321E30075EE4A /* MigrationDemo.xcdatamodeld */; };
|
||||
B569650C1B2B36E10075EE4A /* FetchingAndQueryingDemoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B569650B1B2B36E10075EE4A /* FetchingAndQueryingDemoViewController.swift */; };
|
||||
B56965181B2E20CC0075EE4A /* TimeZone.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56965171B2E20CC0075EE4A /* TimeZone.swift */; };
|
||||
B569651A1B30888A0075EE4A /* FetchingResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56965191B30888A0075EE4A /* FetchingResultsViewController.swift */; };
|
||||
B569651C1B30889A0075EE4A /* QueryingResultsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B569651B1B30889A0075EE4A /* QueryingResultsViewController.swift */; };
|
||||
B583A9201AF5F542001F76AF /* CoreStore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B583A91B1AF5F4F4001F76AF /* CoreStore.framework */; };
|
||||
B583A9211AF5F542001F76AF /* CoreStore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B583A91B1AF5F4F4001F76AF /* CoreStore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
B5D9C9191B20AB1900E64F0E /* GCDKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5D9C9181B20AB1900E64F0E /* GCDKit.framework */; };
|
||||
B5D9C91A1B20AB1900E64F0E /* GCDKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B5D9C9181B20AB1900E64F0E /* GCDKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
B5E7240F1B11F993006FB83F /* TwitterAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E7240E1B11F993006FB83F /* TwitterAccount.swift */; };
|
||||
B5E724111B11F994006FB83F /* FacebookAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E724101B11F994006FB83F /* FacebookAccount.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -98,10 +104,17 @@
|
||||
B566E3291B117B1F00F4F0C6 /* StackSetupDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StackSetupDemoViewController.swift; sourceTree = "<group>"; };
|
||||
B566E3311B11DF3200F4F0C6 /* UserAccount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserAccount.swift; sourceTree = "<group>"; };
|
||||
B56964C81B20AC780075EE4A /* CustomLoggerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomLoggerViewController.swift; sourceTree = "<group>"; };
|
||||
B56964D61B231AE90075EE4A /* StackSetupDemo.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = StackSetupDemo.xcdatamodel; sourceTree = "<group>"; };
|
||||
B56964D91B231BCA0075EE4A /* MaleAccount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MaleAccount.swift; sourceTree = "<group>"; };
|
||||
B56964DB1B231BCB0075EE4A /* FemaleAccount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FemaleAccount.swift; sourceTree = "<group>"; };
|
||||
B56964DE1B2321E30075EE4A /* MigrationDemo.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MigrationDemo.xcdatamodel; sourceTree = "<group>"; };
|
||||
B56964E01B2326F30075EE4A /* MigrationDemoV2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MigrationDemoV2.xcdatamodel; sourceTree = "<group>"; };
|
||||
B569650B1B2B36E10075EE4A /* FetchingAndQueryingDemoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchingAndQueryingDemoViewController.swift; sourceTree = "<group>"; };
|
||||
B56965171B2E20CC0075EE4A /* TimeZone.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimeZone.swift; sourceTree = "<group>"; };
|
||||
B56965191B30888A0075EE4A /* FetchingResultsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FetchingResultsViewController.swift; sourceTree = "<group>"; };
|
||||
B569651B1B30889A0075EE4A /* QueryingResultsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryingResultsViewController.swift; sourceTree = "<group>"; };
|
||||
B583A9141AF5F4F3001F76AF /* CoreStore.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CoreStore.xcodeproj; path = ../CoreStore.xcodeproj; sourceTree = "<group>"; };
|
||||
B5D9C9181B20AB1900E64F0E /* GCDKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = GCDKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B5E7240E1B11F993006FB83F /* TwitterAccount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TwitterAccount.swift; sourceTree = "<group>"; };
|
||||
B5E724101B11F994006FB83F /* FacebookAccount.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FacebookAccount.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -175,11 +188,14 @@
|
||||
B566E3271B117AE700F4F0C6 /* Stack Setup Demo */,
|
||||
B503FADA1AFDC71700F90881 /* List and Object Observers Demo */,
|
||||
B52977DB1B120F2C003D50A5 /* Transactions Demo */,
|
||||
B56965091B2B35370075EE4A /* Fetching and Querying Demo */,
|
||||
B56964C61B20AC200075EE4A /* Loggers Demo */,
|
||||
B54AAD571AF4D26E00848AE0 /* Main.storyboard */,
|
||||
B54AAD5A1AF4D26E00848AE0 /* Images.xcassets */,
|
||||
B54AAD5C1AF4D26E00848AE0 /* LaunchScreen.xib */,
|
||||
B54AAD501AF4D26E00848AE0 /* CoreStoreDemo.xcdatamodeld */,
|
||||
B56964D51B231AE90075EE4A /* StackSetupDemo.xcdatamodeld */,
|
||||
B56964DD1B2321E30075EE4A /* MigrationDemo.xcdatamodeld */,
|
||||
B54AAD4C1AF4D26E00848AE0 /* Supporting Files */,
|
||||
);
|
||||
path = CoreStoreDemo;
|
||||
@@ -196,8 +212,8 @@
|
||||
B566E3271B117AE700F4F0C6 /* Stack Setup Demo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5E724101B11F994006FB83F /* FacebookAccount.swift */,
|
||||
B5E7240E1B11F993006FB83F /* TwitterAccount.swift */,
|
||||
B56964DB1B231BCB0075EE4A /* FemaleAccount.swift */,
|
||||
B56964D91B231BCA0075EE4A /* MaleAccount.swift */,
|
||||
B566E3311B11DF3200F4F0C6 /* UserAccount.swift */,
|
||||
B566E3291B117B1F00F4F0C6 /* StackSetupDemoViewController.swift */,
|
||||
);
|
||||
@@ -212,6 +228,17 @@
|
||||
path = "Loggers Demo";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B56965091B2B35370075EE4A /* Fetching and Querying Demo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B56965171B2E20CC0075EE4A /* TimeZone.swift */,
|
||||
B569650B1B2B36E10075EE4A /* FetchingAndQueryingDemoViewController.swift */,
|
||||
B56965191B30888A0075EE4A /* FetchingResultsViewController.swift */,
|
||||
B569651B1B30889A0075EE4A /* QueryingResultsViewController.swift */,
|
||||
);
|
||||
path = "Fetching and Querying Demo";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B583A9151AF5F4F3001F76AF /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -317,20 +344,26 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B56965181B2E20CC0075EE4A /* TimeZone.swift in Sources */,
|
||||
B52977DD1B120F3B003D50A5 /* TransactionsDemoViewController.swift in Sources */,
|
||||
B56964DF1B2321E30075EE4A /* MigrationDemo.xcdatamodeld in Sources */,
|
||||
B52977E41B121635003D50A5 /* Place.swift in Sources */,
|
||||
B569650C1B2B36E10075EE4A /* FetchingAndQueryingDemoViewController.swift in Sources */,
|
||||
B569651A1B30888A0075EE4A /* FetchingResultsViewController.swift in Sources */,
|
||||
B503FAE01AFDC71700F90881 /* ObjectObserverDemoViewController.swift in Sources */,
|
||||
B52977D91B120B80003D50A5 /* ObserversViewController.swift in Sources */,
|
||||
B56964C91B20AC780075EE4A /* CustomLoggerViewController.swift in Sources */,
|
||||
B566E32A1B117B1F00F4F0C6 /* StackSetupDemoViewController.swift in Sources */,
|
||||
B5E724111B11F994006FB83F /* FacebookAccount.swift in Sources */,
|
||||
B5E7240F1B11F993006FB83F /* TwitterAccount.swift in Sources */,
|
||||
B56964DA1B231BCA0075EE4A /* MaleAccount.swift in Sources */,
|
||||
B566E3321B11DF3200F4F0C6 /* UserAccount.swift in Sources */,
|
||||
B54AAD521AF4D26E00848AE0 /* CoreStoreDemo.xcdatamodeld in Sources */,
|
||||
B503FAE11AFDC71700F90881 /* Palette.swift in Sources */,
|
||||
B503FAE21AFDC71700F90881 /* PaletteTableViewCell.swift in Sources */,
|
||||
B503FADF1AFDC71700F90881 /* ObjectListObserverDemoViewController.swift in Sources */,
|
||||
B54AAD4F1AF4D26E00848AE0 /* AppDelegate.swift in Sources */,
|
||||
B56964D71B231AE90075EE4A /* StackSetupDemo.xcdatamodeld in Sources */,
|
||||
B56964DC1B231BCB0075EE4A /* FemaleAccount.swift in Sources */,
|
||||
B569651C1B30889A0075EE4A /* QueryingResultsViewController.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -516,6 +549,27 @@
|
||||
sourceTree = "<group>";
|
||||
versionGroupType = wrapper.xcdatamodel;
|
||||
};
|
||||
B56964D51B231AE90075EE4A /* StackSetupDemo.xcdatamodeld */ = {
|
||||
isa = XCVersionGroup;
|
||||
children = (
|
||||
B56964D61B231AE90075EE4A /* StackSetupDemo.xcdatamodel */,
|
||||
);
|
||||
currentVersion = B56964D61B231AE90075EE4A /* StackSetupDemo.xcdatamodel */;
|
||||
path = StackSetupDemo.xcdatamodeld;
|
||||
sourceTree = "<group>";
|
||||
versionGroupType = wrapper.xcdatamodel;
|
||||
};
|
||||
B56964DD1B2321E30075EE4A /* MigrationDemo.xcdatamodeld */ = {
|
||||
isa = XCVersionGroup;
|
||||
children = (
|
||||
B56964E01B2326F30075EE4A /* MigrationDemoV2.xcdatamodel */,
|
||||
B56964DE1B2321E30075EE4A /* MigrationDemo.xcdatamodel */,
|
||||
);
|
||||
currentVersion = B56964E01B2326F30075EE4A /* MigrationDemoV2.xcdatamodel */;
|
||||
path = MigrationDemo.xcdatamodeld;
|
||||
sourceTree = "<group>";
|
||||
versionGroupType = wrapper.xcdatamodel;
|
||||
};
|
||||
/* End XCVersionGroup section */
|
||||
};
|
||||
rootObject = B54AAD411AF4D26E00848AE0 /* Project object */;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<key>4B60F1BCB491FF717C56441AE7783C74F417BE48</key>
|
||||
<string>../../..</string>
|
||||
<key>8B2E522D57154DFA93A06982C36315ECBEA4FA97</key>
|
||||
<string>../../../Libraries/GCDKit</string>
|
||||
<string>../../..Libraries/GCDKit</string>
|
||||
</dict>
|
||||
<key>IDESourceControlProjectURL</key>
|
||||
<string>github.com:JohnEstropia/CoreStore.git</string>
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "4B60F1BCB491FF717C56441AE7783C74F417BE48",
|
||||
"DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : {
|
||||
|
||||
},
|
||||
"DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
|
||||
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : 0,
|
||||
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : 0
|
||||
},
|
||||
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "B6855E48-4B19-4321-B1C7-CB2706E12777",
|
||||
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
|
||||
"8B2E522D57154DFA93A06982C36315ECBEA4FA97" : "CoreStoreLibraries\/GCDKit",
|
||||
"4B60F1BCB491FF717C56441AE7783C74F417BE48" : "CoreStore"
|
||||
},
|
||||
"DVTSourceControlWorkspaceBlueprintNameKey" : "CoreStoreDemo",
|
||||
"DVTSourceControlWorkspaceBlueprintVersion" : 203,
|
||||
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "CoreStoreDemo\/CoreStoreDemo.xcodeproj",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
|
||||
{
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:JohnEstropia\/CoreStore.git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "4B60F1BCB491FF717C56441AE7783C74F417BE48"
|
||||
},
|
||||
{
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "github.com:JohnEstropia\/GCDKit.git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
|
||||
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "8B2E522D57154DFA93A06982C36315ECBEA4FA97"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0630"
|
||||
version = "1.3">
|
||||
version = "1.8">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
@@ -38,6 +38,8 @@
|
||||
ReferencedContainer = "container:CoreStoreDemo.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
@@ -47,6 +49,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Bucket
|
||||
type = "1"
|
||||
version = "2.0">
|
||||
<Breakpoints>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "../CoreStore/Migrating/DataStack+Migration.swift"
|
||||
timestampString = "457102815.005196"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "80"
|
||||
endingLineNumber = "80"
|
||||
landmarkName = "needsMigrationForSQLiteStore(fileURL:configuration:)"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
|
||||
<BreakpointContent
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
filePath = "../CoreStore/Migrating/DataStack+Migration.swift"
|
||||
timestampString = "457102823.242858"
|
||||
startingColumnNumber = "9223372036854775807"
|
||||
endingColumnNumber = "9223372036854775807"
|
||||
startingLineNumber = "165"
|
||||
endingLineNumber = "165"
|
||||
landmarkName = "upgradeSQLiteStoreIfNeeded(fileURL:configuration:completion:)"
|
||||
landmarkType = "5">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
</Breakpoints>
|
||||
</Bucket>
|
||||
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>SchemeUserState</key>
|
||||
<dict>
|
||||
<key>CoreStoreDemo.xcscheme</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
<dict>
|
||||
<key>B54AAD481AF4D26E00848AE0</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -150,7 +150,7 @@
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ekW-PJ-mbo" id="CYq-mg-PVS">
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Placemark" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="UbU-Kd-yrY">
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Placemarks" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="UbU-Kd-yrY">
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
@@ -168,6 +168,29 @@
|
||||
<segue destination="jPl-fH-NlD" kind="show" id="g1J-LG-mxf"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="C8Y-0y-lEG" detailTextLabel="jZw-qE-0ws" style="IBUITableViewCellStyleSubtitle" id="ph1-8z-C1m">
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ph1-8z-C1m" id="nNz-rd-ksg">
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Time Zones" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="C8Y-0y-lEG">
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Fetching objects and raw values" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="jZw-qE-0ws">
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</tableViewCellContentView>
|
||||
<connections>
|
||||
<segue destination="qbj-MK-nIY" kind="show" id="1xo-NL-U8c"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="ZfY-Aq-Ykq" detailTextLabel="QzD-9b-k1j" style="IBUITableViewCellStyleSubtitle" id="wyK-rk-3tI">
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="wyK-rk-3tI" id="fLd-KK-QcW">
|
||||
@@ -191,26 +214,6 @@
|
||||
<segue destination="5yy-0N-QDU" kind="show" id="5D7-Xp-1HT"/>
|
||||
</connections>
|
||||
</tableViewCell>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" textLabel="C8Y-0y-lEG" detailTextLabel="jZw-qE-0ws" style="IBUITableViewCellStyleSubtitle" id="ph1-8z-C1m">
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ph1-8z-C1m" id="nNz-rd-ksg">
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="C8Y-0y-lEG">
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Fetching objects and raw values" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="jZw-qE-0ws">
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
</cells>
|
||||
</tableViewSection>
|
||||
</sections>
|
||||
@@ -223,7 +226,7 @@
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="Xgp-Zn-Sbp" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="2982" y="1325"/>
|
||||
<point key="canvasLocation" x="2634" y="2013"/>
|
||||
</scene>
|
||||
<!--Object Observer-->
|
||||
<scene sceneID="Y7v-tc-8cX">
|
||||
@@ -417,7 +420,7 @@
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="sm4-t7-KeT" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="2170" y="1325"/>
|
||||
<point key="canvasLocation" x="1822" y="2013"/>
|
||||
</scene>
|
||||
<!--List Observer-->
|
||||
<scene sceneID="gkX-bd-Rel">
|
||||
@@ -559,7 +562,7 @@
|
||||
</objects>
|
||||
<point key="canvasLocation" x="4404" y="1546"/>
|
||||
</scene>
|
||||
<!--Placemark-->
|
||||
<!--Placemarks-->
|
||||
<scene sceneID="LRD-q1-hw1">
|
||||
<objects>
|
||||
<viewController id="jPl-fH-NlD" customClass="TransactionsDemoViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
|
||||
@@ -587,7 +590,7 @@
|
||||
</constraints>
|
||||
</view>
|
||||
<extendedEdge key="edgesForExtendedLayout" bottom="YES"/>
|
||||
<navigationItem key="navigationItem" title="Placemark" id="s5y-WX-W5w"/>
|
||||
<navigationItem key="navigationItem" title="Placemarks" id="s5y-WX-W5w"/>
|
||||
<connections>
|
||||
<outlet property="mapView" destination="V2U-0R-Ts0" id="X6a-Bp-psg"/>
|
||||
</connections>
|
||||
@@ -653,7 +656,7 @@
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="gKf-zW-DSX" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="3694" y="2792"/>
|
||||
<point key="canvasLocation" x="3694" y="3412"/>
|
||||
</scene>
|
||||
<!--Navigation Controller-->
|
||||
<scene sceneID="3ih-RN-P43">
|
||||
@@ -680,6 +683,172 @@
|
||||
</objects>
|
||||
<point key="canvasLocation" x="4404" y="1144.5"/>
|
||||
</scene>
|
||||
<!--Time Zones-->
|
||||
<scene sceneID="nFT-bo-7y9">
|
||||
<objects>
|
||||
<viewController automaticallyAdjustsScrollViewInsets="NO" id="qbj-MK-nIY" customClass="FetchingAndQueryingDemoViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="dgu-PC-LiB"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="DlN-cN-JXd"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="eC3-ql-d2o">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="WGY-kX-mAx">
|
||||
<rect key="frame" x="0.0" y="64" width="600" height="536"/>
|
||||
<color key="backgroundColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="separatorColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<view key="tableHeaderView" contentMode="scaleToFill" id="iaH-1W-Sbo">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="80"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="bordered" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="YVj-dA-fyV">
|
||||
<rect key="frame" x="20" y="26" width="560" height="29"/>
|
||||
<segments>
|
||||
<segment title="Fetch"/>
|
||||
<segment title="Query"/>
|
||||
</segments>
|
||||
<color key="tintColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<connections>
|
||||
<action selector="segmentedControlValueChanged:" destination="qbj-MK-nIY" eventType="valueChanged" id="Wok-dl-uq7"/>
|
||||
</connections>
|
||||
</segmentedControl>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="0.80000000000000004" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="YVj-dA-fyV" firstAttribute="leading" secondItem="iaH-1W-Sbo" secondAttribute="leading" constant="20" id="1dX-t7-dyR"/>
|
||||
<constraint firstAttribute="centerY" secondItem="YVj-dA-fyV" secondAttribute="centerY" id="HXU-Z7-jfu"/>
|
||||
<constraint firstAttribute="trailing" secondItem="YVj-dA-fyV" secondAttribute="trailing" constant="20" id="yZc-YH-2a6"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="6db-P0-6Ms" style="IBUITableViewCellStyleDefault" id="vUr-WV-qur">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="vUr-WV-qur" id="Vr0-hE-cn9">
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Title" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="6db-P0-6Ms">
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="18"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
</prototypes>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="qbj-MK-nIY" id="EzZ-Ai-1Ws"/>
|
||||
<outlet property="delegate" destination="qbj-MK-nIY" id="nxB-y6-zeW"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="WGY-kX-mAx" firstAttribute="top" secondItem="dgu-PC-LiB" secondAttribute="bottom" id="0pS-cU-ibk"/>
|
||||
<constraint firstAttribute="trailing" secondItem="WGY-kX-mAx" secondAttribute="trailing" id="NeY-g5-CaB"/>
|
||||
<constraint firstItem="WGY-kX-mAx" firstAttribute="leading" secondItem="eC3-ql-d2o" secondAttribute="leading" id="hmg-4g-RJR"/>
|
||||
<constraint firstItem="DlN-cN-JXd" firstAttribute="top" secondItem="WGY-kX-mAx" secondAttribute="bottom" id="noT-BW-H0m"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" title="Time Zones" id="iCK-OF-qH9"/>
|
||||
<connections>
|
||||
<outlet property="segmentedControl" destination="YVj-dA-fyV" id="BPp-f2-VxW"/>
|
||||
<outlet property="tableView" destination="WGY-kX-mAx" id="7kc-fB-s7N"/>
|
||||
<segue destination="tIs-pN-OgO" kind="show" identifier="FetchingResultsViewController" id="AoY-Dn-t34"/>
|
||||
<segue destination="o9D-Xm-13g" kind="show" identifier="QueryingResultsViewController" id="0RK-WR-PQ9"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="blS-OT-gHK" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="3694" y="2712"/>
|
||||
</scene>
|
||||
<!--Fetch Results-->
|
||||
<scene sceneID="kk7-cC-Fj8">
|
||||
<objects>
|
||||
<tableViewController id="tIs-pN-OgO" customClass="FetchingResultsViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="60" sectionHeaderHeight="36" sectionFooterHeight="22" id="tVl-tT-UDk">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="separatorColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="RgX-yK-1L2" detailTextLabel="QZ4-A2-x4h" style="IBUITableViewCellStyleSubtitle" id="uBt-Iy-nWP">
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="uBt-Iy-nWP" id="6SD-ur-9zp">
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="name" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="RgX-yK-1L2">
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="offset" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="QZ4-A2-x4h">
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
</prototypes>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="tIs-pN-OgO" id="6Bt-9f-xrK"/>
|
||||
<outlet property="delegate" destination="tIs-pN-OgO" id="unW-dH-8W2"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<navigationItem key="navigationItem" title="Fetch Results" id="q8f-ux-g9l"/>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="oNB-PO-h8i" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="4404" y="2369"/>
|
||||
</scene>
|
||||
<!--Query Results-->
|
||||
<scene sceneID="eUn-Bw-RNd">
|
||||
<objects>
|
||||
<tableViewController id="o9D-Xm-13g" customClass="QueryingResultsViewController" customModule="CoreStoreDemo" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="60" sectionHeaderHeight="36" sectionFooterHeight="22" id="bMh-zR-xwu">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<color key="separatorColor" red="0.20392156859999999" green="0.28627450980000002" blue="0.36862745099999999" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<prototypes>
|
||||
<tableViewCell contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="UITableViewCell" textLabel="Syt-QJ-KXg" detailTextLabel="yHS-dP-IKS" style="IBUITableViewCellStyleSubtitle" id="q7Q-aF-Ftl">
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="q7Q-aF-Ftl" id="fc3-eg-yes">
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<subviews>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="name" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Syt-QJ-KXg">
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="20"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="offset" lineBreakMode="wordWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="yHS-dP-IKS">
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
||||
<color key="textColor" red="0.17254901959999999" green="0.24313725489999999" blue="0.31372549020000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
</tableViewCellContentView>
|
||||
</tableViewCell>
|
||||
</prototypes>
|
||||
<connections>
|
||||
<outlet property="dataSource" destination="o9D-Xm-13g" id="X7V-ld-5ea"/>
|
||||
<outlet property="delegate" destination="o9D-Xm-13g" id="h9U-qa-e4j"/>
|
||||
</connections>
|
||||
</tableView>
|
||||
<navigationItem key="navigationItem" title="Query Results" id="yuZ-gO-DnV"/>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="VxN-sF-a59" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="4404" y="3055"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="second" width="30" height="30"/>
|
||||
|
||||
@@ -13,26 +13,25 @@
|
||||
<attribute name="subtitle" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="title" optional="YES" attributeType="String" syncable="YES"/>
|
||||
</entity>
|
||||
<entity name="UserAccount" representedClassName="CoreStoreDemo.UserAccount" syncable="YES">
|
||||
<attribute name="accountType" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="friends" optional="YES" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
|
||||
<entity name="TimeZone" representedClassName="CoreStoreDemo.TimeZone" syncable="YES">
|
||||
<attribute name="abbreviation" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="daylightSavingTimeOffset" optional="YES" attributeType="Double" defaultValueString="0.0" syncable="YES"/>
|
||||
<attribute name="hasDaylightSavingTime" optional="YES" attributeType="Boolean" syncable="YES"/>
|
||||
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="secondsFromGMT" optional="YES" attributeType="Integer 32" defaultValueString="0.0" syncable="YES"/>
|
||||
</entity>
|
||||
<configuration name="FetchingAndQueryingDemo">
|
||||
<memberEntity name="TimeZone"/>
|
||||
</configuration>
|
||||
<configuration name="ObservingDemo">
|
||||
<memberEntity name="Palette"/>
|
||||
</configuration>
|
||||
<configuration name="SetupDemo_Jane">
|
||||
<memberEntity name="UserAccount"/>
|
||||
</configuration>
|
||||
<configuration name="SetupDemo_John">
|
||||
<memberEntity name="UserAccount"/>
|
||||
</configuration>
|
||||
<configuration name="TransactionsDemo">
|
||||
<memberEntity name="Place"/>
|
||||
</configuration>
|
||||
<elements>
|
||||
<element name="Palette" positionX="261" positionY="189" width="128" height="105"/>
|
||||
<element name="Place" positionX="261" positionY="225" width="128" height="105"/>
|
||||
<element name="UserAccount" positionX="261" positionY="216" width="128" height="90"/>
|
||||
<element name="TimeZone" positionX="297" positionY="270" width="128" height="120"/>
|
||||
</elements>
|
||||
</model>
|
||||
@@ -0,0 +1,290 @@
|
||||
//
|
||||
// FetchingAndQueryingDemoViewController.swift
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/12.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import CoreStore
|
||||
|
||||
|
||||
private struct Static {
|
||||
|
||||
static let timeZonesStack: DataStack = {
|
||||
|
||||
let dataStack = DataStack()
|
||||
dataStack.addSQLiteStoreAndWait(
|
||||
"TimeZoneDemo.sqlite",
|
||||
configuration: "FetchingAndQueryingDemo",
|
||||
resetStoreOnMigrationFailure: true
|
||||
)
|
||||
|
||||
dataStack.beginSynchronous { (transaction) -> Void in
|
||||
|
||||
transaction.deleteAll(From(TimeZone))
|
||||
|
||||
for name in NSTimeZone.knownTimeZoneNames() as! [String] {
|
||||
|
||||
let rawTimeZone = NSTimeZone(name: name)!
|
||||
let cachedTimeZone = transaction.create(Into(TimeZone))
|
||||
|
||||
cachedTimeZone.name = rawTimeZone.name
|
||||
cachedTimeZone.abbreviation = rawTimeZone.abbreviation ?? ""
|
||||
cachedTimeZone.secondsFromGMT = Int32(rawTimeZone.secondsFromGMT)
|
||||
cachedTimeZone.hasDaylightSavingTime = rawTimeZone.daylightSavingTime
|
||||
cachedTimeZone.daylightSavingTimeOffset = rawTimeZone.daylightSavingTimeOffset
|
||||
}
|
||||
|
||||
transaction.commit()
|
||||
}
|
||||
|
||||
return dataStack
|
||||
}()
|
||||
}
|
||||
|
||||
|
||||
// MARK: - FetchingAndQueryingDemoViewController
|
||||
|
||||
class FetchingAndQueryingDemoViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
|
||||
|
||||
// MARK: UIViewController
|
||||
|
||||
override func viewDidAppear(animated: Bool) {
|
||||
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
if self.didAppearOnce {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
self.didAppearOnce = true
|
||||
|
||||
let alert = UIAlertController(
|
||||
title: "Fetch and Query Demo",
|
||||
message: "This demo shows how to execute fetches and queries.\n\nEach menu item executes and displays a preconfigured fetch/query.",
|
||||
preferredStyle: .Alert
|
||||
)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
|
||||
self.presentViewController(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
|
||||
|
||||
super.prepareForSegue(segue, sender: sender)
|
||||
|
||||
if let indexPath = sender as? NSIndexPath {
|
||||
|
||||
switch segue.destinationViewController {
|
||||
|
||||
case let controller as FetchingResultsViewController:
|
||||
let item = self.fetchingItems[indexPath.row]
|
||||
controller.setTimeZones(item.fetch(), title: item.title)
|
||||
|
||||
case let controller as QueryingResultsViewController:
|
||||
let item = self.queryingItems[indexPath.row]
|
||||
controller.setValue(item.query(), title: item.title)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: UITableViewDataSource
|
||||
|
||||
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
switch self.segmentedControl?.selectedSegmentIndex {
|
||||
|
||||
case .Some(Section.Fetching.rawValue):
|
||||
return self.fetchingItems.count
|
||||
|
||||
case .Some(Section.Querying.rawValue):
|
||||
return self.queryingItems.count
|
||||
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
|
||||
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell") as! UITableViewCell
|
||||
|
||||
switch self.segmentedControl?.selectedSegmentIndex {
|
||||
|
||||
case .Some(Section.Fetching.rawValue):
|
||||
cell.textLabel?.text = self.fetchingItems[indexPath.row].title
|
||||
|
||||
case .Some(Section.Querying.rawValue):
|
||||
cell.textLabel?.text = self.queryingItems[indexPath.row].title
|
||||
|
||||
default:
|
||||
cell.textLabel?.text = nil
|
||||
}
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
|
||||
// MARK: UITableViewDelegate
|
||||
|
||||
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
|
||||
|
||||
tableView.deselectRowAtIndexPath(indexPath, animated: true)
|
||||
|
||||
switch self.segmentedControl?.selectedSegmentIndex {
|
||||
|
||||
case .Some(Section.Fetching.rawValue):
|
||||
self.performSegueWithIdentifier("FetchingResultsViewController", sender: indexPath)
|
||||
|
||||
case .Some(Section.Querying.rawValue):
|
||||
self.performSegueWithIdentifier("QueryingResultsViewController", sender: indexPath)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private enum Section: Int {
|
||||
|
||||
case Fetching
|
||||
case Querying
|
||||
}
|
||||
|
||||
private let fetchingItems = [
|
||||
(
|
||||
title: "All Time Zones",
|
||||
fetch: { () -> [TimeZone] in
|
||||
|
||||
return Static.timeZonesStack.fetchAll(
|
||||
From(TimeZone),
|
||||
OrderBy(.Ascending("name"))
|
||||
)!
|
||||
}
|
||||
),
|
||||
(
|
||||
title: "Time Zones in Asia",
|
||||
fetch: { () -> [TimeZone] in
|
||||
|
||||
return Static.timeZonesStack.fetchAll(
|
||||
From(TimeZone),
|
||||
Where("%K BEGINSWITH[c] %@", "name", "Asia"),
|
||||
OrderBy(.Ascending("secondsFromGMT"))
|
||||
)!
|
||||
}
|
||||
),
|
||||
(
|
||||
title: "Time Zones in America and Europe",
|
||||
fetch: { () -> [TimeZone] in
|
||||
|
||||
return Static.timeZonesStack.fetchAll(
|
||||
From(TimeZone),
|
||||
Where("%K BEGINSWITH[c] %@", "name", "America")
|
||||
|| Where("%K BEGINSWITH[c] %@", "name", "Europe"),
|
||||
OrderBy(.Ascending("secondsFromGMT"))
|
||||
)!
|
||||
}
|
||||
),
|
||||
(
|
||||
title: "All Time Zones Except America",
|
||||
fetch: { () -> [TimeZone] in
|
||||
|
||||
return Static.timeZonesStack.fetchAll(
|
||||
From(TimeZone),
|
||||
!Where("%K BEGINSWITH[c] %@", "name", "America"),
|
||||
OrderBy(.Ascending("secondsFromGMT"))
|
||||
)!
|
||||
}
|
||||
),
|
||||
(
|
||||
title: "Time Zones with Summer Time",
|
||||
fetch: { () -> [TimeZone] in
|
||||
|
||||
return Static.timeZonesStack.fetchAll(
|
||||
From(TimeZone),
|
||||
Where("hasDaylightSavingTime", isEqualTo: true),
|
||||
OrderBy(.Ascending("name"))
|
||||
)!
|
||||
}
|
||||
)
|
||||
]
|
||||
|
||||
private let queryingItems = [
|
||||
(
|
||||
title: "Number of Time Zones",
|
||||
query: { () -> AnyObject in
|
||||
|
||||
return Static.timeZonesStack.queryValue(
|
||||
From(TimeZone),
|
||||
Select<NSNumber>(.Count("name"))
|
||||
)!
|
||||
}
|
||||
),
|
||||
(
|
||||
title: "Abbreviation For Tokyo's Time Zone",
|
||||
query: { () -> AnyObject in
|
||||
|
||||
return Static.timeZonesStack.queryValue(
|
||||
From(TimeZone),
|
||||
Select<String>("abbreviation"),
|
||||
Where("%K ENDSWITH[c] %@", "name", "Tokyo")
|
||||
)!
|
||||
}
|
||||
),
|
||||
(
|
||||
title: "All Abbreviations",
|
||||
query: { () -> AnyObject in
|
||||
|
||||
return Static.timeZonesStack.queryAttributes(
|
||||
From(TimeZone),
|
||||
Select<NSDictionary>("name", "abbreviation"),
|
||||
OrderBy(.Ascending("name"))
|
||||
)!
|
||||
}
|
||||
),
|
||||
(
|
||||
title: "Number of Countries per Time Zone",
|
||||
query: { () -> AnyObject in
|
||||
|
||||
return Static.timeZonesStack.queryAttributes(
|
||||
From(TimeZone),
|
||||
Select<NSDictionary>(.Count("abbreviation"), "abbreviation"),
|
||||
GroupBy("abbreviation"),
|
||||
OrderBy(.Ascending("secondsFromGMT"), .Ascending("name"))
|
||||
)!
|
||||
}
|
||||
),
|
||||
(
|
||||
title: "Number of Countries with Summer Time",
|
||||
query: { () -> AnyObject in
|
||||
|
||||
return Static.timeZonesStack.queryAttributes(
|
||||
From(TimeZone),
|
||||
Select<NSDictionary>(
|
||||
.Count("hasDaylightSavingTime", As: "numberOfCountries"),
|
||||
"hasDaylightSavingTime"
|
||||
),
|
||||
GroupBy("hasDaylightSavingTime"),
|
||||
OrderBy(.Descending("hasDaylightSavingTime"))
|
||||
)!
|
||||
}
|
||||
)
|
||||
]
|
||||
|
||||
var didAppearOnce = false
|
||||
|
||||
@IBOutlet dynamic weak var segmentedControl: UISegmentedControl?
|
||||
@IBOutlet dynamic weak var tableView: UITableView?
|
||||
|
||||
@IBAction dynamic func segmentedControlValueChanged(sender: AnyObject?) {
|
||||
|
||||
self.tableView?.reloadData()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// FetchingResultsViewController.swift
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/17.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
// MARK: - FetchingResultsViewController
|
||||
|
||||
class FetchingResultsViewController: UITableViewController {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
func setTimeZones(timeZones: [TimeZone]?, title: String) {
|
||||
|
||||
self.timeZones += timeZones ?? []
|
||||
self.sectionTitle = title
|
||||
|
||||
self.tableView?.reloadData()
|
||||
}
|
||||
|
||||
|
||||
// MARK: UIViewController
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
||||
super.viewDidLoad()
|
||||
|
||||
self.tableView.estimatedRowHeight = 60
|
||||
self.tableView.rowHeight = UITableViewAutomaticDimension
|
||||
}
|
||||
|
||||
|
||||
// MARK: UITableViewDataSource
|
||||
|
||||
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
|
||||
return self.timeZones.count
|
||||
}
|
||||
|
||||
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
|
||||
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell", forIndexPath: indexPath) as! UITableViewCell
|
||||
|
||||
let timeZone = self.timeZones[indexPath.row]
|
||||
cell.textLabel?.text = timeZone.name
|
||||
cell.detailTextLabel?.text = timeZone.abbreviation
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
|
||||
// MARK: UITableViewDelegate
|
||||
|
||||
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
|
||||
return self.sectionTitle
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
var timeZones = [TimeZone]()
|
||||
var sectionTitle: String?
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
//
|
||||
// QueryingResultsViewController.swift
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/17.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class QueryingResultsViewController: UITableViewController {
|
||||
|
||||
// MARK: Public
|
||||
|
||||
func setValue(value: AnyObject?, title: String) {
|
||||
|
||||
switch value {
|
||||
|
||||
case .Some(let array as [AnyObject]):
|
||||
self.values = array.map { (item: AnyObject) -> (title: String, detail: String) in
|
||||
(
|
||||
title: item.description,
|
||||
detail: _stdlib_getDemangledTypeName(item)
|
||||
)
|
||||
}
|
||||
|
||||
case .Some(let item):
|
||||
self.values = [
|
||||
(
|
||||
title: item.description,
|
||||
detail: _stdlib_getDemangledTypeName(item)
|
||||
)
|
||||
]
|
||||
|
||||
default:
|
||||
self.values = []
|
||||
}
|
||||
|
||||
self.sectionTitle = title
|
||||
|
||||
self.tableView?.reloadData()
|
||||
}
|
||||
|
||||
|
||||
// MARK: UIViewController
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
||||
super.viewDidLoad()
|
||||
|
||||
self.tableView.estimatedRowHeight = 60
|
||||
self.tableView.rowHeight = UITableViewAutomaticDimension
|
||||
}
|
||||
|
||||
|
||||
// MARK: UITableViewDataSource
|
||||
|
||||
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
|
||||
return self.values.count
|
||||
}
|
||||
|
||||
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
|
||||
|
||||
let cell = tableView.dequeueReusableCellWithIdentifier("UITableViewCell", forIndexPath: indexPath) as! UITableViewCell
|
||||
|
||||
let value = self.values[indexPath.row]
|
||||
|
||||
cell.textLabel?.text = value.title
|
||||
cell.detailTextLabel?.text = value.detail
|
||||
|
||||
return cell
|
||||
}
|
||||
|
||||
|
||||
// MARK: UITableViewDelegate
|
||||
|
||||
override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
|
||||
return self.sectionTitle
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
var values: [(title: String, detail: String)] = []
|
||||
var sectionTitle: String?
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// TimeZone.swift
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/15.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
class TimeZone: NSManagedObject {
|
||||
|
||||
@NSManaged var secondsFromGMT: Int32
|
||||
@NSManaged var abbreviation: String
|
||||
@NSManaged var hasDaylightSavingTime: Bool
|
||||
@NSManaged var daylightSavingTimeOffset: Double
|
||||
@NSManaged var name: String
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@ private struct Static {
|
||||
|
||||
static let palettes: ManagedObjectListController<Palette> = {
|
||||
|
||||
CoreStore.addSQLiteStore(
|
||||
CoreStore.addSQLiteStoreAndWait(
|
||||
"ColorsDemo.sqlite",
|
||||
configuration: "ObservingDemo",
|
||||
resetStoreOnMigrationFailure: true
|
||||
|
||||
@@ -21,7 +21,7 @@ class ObserversViewController: UIViewController {
|
||||
|
||||
let alert = UIAlertController(
|
||||
title: "Observers Demo",
|
||||
message: "This demo shows how to observe changes to a list of objects. The top and bottom view controllers both observe a single shared \"ManagedObjectListController\" instance.\n\nTap on a row to see another demo that shows how to observe changes to a single object using a \"ManagedObjectController\".",
|
||||
message: "This demo shows how to observe changes to a list of objects. The top and bottom view controllers both observe a single shared \"ManagedObjectListController\" instance.\n\nTap on a row to see how to observe changes made to a single object using a \"ManagedObjectController\".",
|
||||
preferredStyle: .Alert
|
||||
)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
|
||||
|
||||
@@ -30,7 +30,7 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
||||
|
||||
super.viewDidLoad()
|
||||
|
||||
self.dataStack.addSQLiteStore("emptyStore.sqlite")
|
||||
self.dataStack.addSQLiteStoreAndWait("emptyStore.sqlite")
|
||||
CoreStore.logger = self
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ class CustomLoggerViewController: UIViewController, CoreStoreLogger {
|
||||
}
|
||||
|
||||
case .Some(1):
|
||||
self.dataStack.addSQLiteStore("emptyStore.sqlite", configuration: "invalidStore")
|
||||
self.dataStack.addSQLiteStoreAndWait("emptyStore.sqlite", configuration: "invalidStore")
|
||||
|
||||
case .Some(2):
|
||||
self.dataStack.beginAsynchronous { (transaction) -> Void in
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges</key>
|
||||
<true/>
|
||||
<key>SnapshotAutomaticallyBeforeSignificantChanges</key>
|
||||
<true/>
|
||||
<key>_XCCurrentVersionName</key>
|
||||
<string>MigrationDemoV2.xcdatamodel</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14D136" minimumToolsVersion="Xcode 4.3" macOSVersion="Automatic" iOSVersion="Automatic">
|
||||
<entity name="Organism" syncable="YES"/>
|
||||
<elements>
|
||||
<element name="Organism" positionX="-36" positionY="9" width="128" height="45"/>
|
||||
</elements>
|
||||
</model>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14D136" minimumToolsVersion="Xcode 4.3" macOSVersion="Automatic" iOSVersion="Automatic">
|
||||
<entity name="Organism" syncable="YES"/>
|
||||
<elements>
|
||||
<element name="Organism" positionX="-36" positionY="9" width="128" height="45"/>
|
||||
</elements>
|
||||
</model>
|
||||
@@ -1,15 +0,0 @@
|
||||
//
|
||||
// FacebookAccount.swift
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/05/24.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
|
||||
// MARK: - FacebookAccount
|
||||
|
||||
class FacebookAccount: TwitterAccount { }
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// FemaleAccount.swift
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/06.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
class FemaleAccount: UserAccount {
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
//
|
||||
// MaleAccount.swift
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/06/06.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
class MaleAccount: UserAccount {
|
||||
|
||||
|
||||
}
|
||||
@@ -12,34 +12,33 @@ import CoreStore
|
||||
|
||||
private struct Static {
|
||||
|
||||
static let johnConfiguration = "SetupDemo_John"
|
||||
static let janeConfiguration = "SetupDemo_Jane"
|
||||
static let maleConfiguration = "MaleAccounts"
|
||||
static let femaleConfiguration = "FemaleAccounts"
|
||||
|
||||
static let facebookStack: DataStack = {
|
||||
|
||||
let dataStack = DataStack(modelName: "CoreStoreDemo")
|
||||
dataStack.addSQLiteStore(
|
||||
"AccountsDemo_FB_John.sqlite",
|
||||
configuration: johnConfiguration,
|
||||
let dataStack = DataStack(modelName: "StackSetupDemo")
|
||||
dataStack.addSQLiteStoreAndWait(
|
||||
"AccountsDemo_FB_Male.sqlite",
|
||||
configuration: maleConfiguration,
|
||||
resetStoreOnMigrationFailure: true
|
||||
)
|
||||
dataStack.addSQLiteStore(
|
||||
"AccountsDemo_FB_Jane.sqlite",
|
||||
configuration: janeConfiguration,
|
||||
dataStack.addSQLiteStoreAndWait(
|
||||
"AccountsDemo_FB_Female.sqlite",
|
||||
configuration: femaleConfiguration,
|
||||
resetStoreOnMigrationFailure: true
|
||||
)
|
||||
|
||||
dataStack.beginSynchronous { (transaction) -> Void in
|
||||
|
||||
transaction.deleteAll(From<UserAccount>(johnConfiguration))
|
||||
transaction.deleteAll(From<UserAccount>(janeConfiguration))
|
||||
transaction.deleteAll(From(UserAccount))
|
||||
|
||||
let account1 = transaction.create(Into<UserAccount>(johnConfiguration))
|
||||
let account1 = transaction.create(Into<MaleAccount>(maleConfiguration))
|
||||
account1.accountType = "Facebook"
|
||||
account1.name = "John Smith HCD"
|
||||
account1.friends = 42
|
||||
|
||||
let account2 = transaction.create(Into<UserAccount>(janeConfiguration))
|
||||
let account2 = transaction.create(Into<FemaleAccount>(femaleConfiguration))
|
||||
account2.accountType = "Facebook"
|
||||
account2.name = "Jane Doe HCD"
|
||||
account2.friends = 314
|
||||
@@ -52,29 +51,28 @@ private struct Static {
|
||||
|
||||
static let twitterStack: DataStack = {
|
||||
|
||||
let dataStack = DataStack(modelName: "CoreStoreDemo")
|
||||
dataStack.addSQLiteStore(
|
||||
"AccountsDemo_TW_John.sqlite",
|
||||
configuration: johnConfiguration,
|
||||
let dataStack = DataStack(modelName: "StackSetupDemo")
|
||||
dataStack.addSQLiteStoreAndWait(
|
||||
"AccountsDemo_TW_Male.sqlite",
|
||||
configuration: maleConfiguration,
|
||||
resetStoreOnMigrationFailure: true
|
||||
)
|
||||
dataStack.addSQLiteStore(
|
||||
"AccountsDemo_TW_Jane.sqlite",
|
||||
configuration: janeConfiguration,
|
||||
dataStack.addSQLiteStoreAndWait(
|
||||
"AccountsDemo_TW_Female.sqlite",
|
||||
configuration: femaleConfiguration,
|
||||
resetStoreOnMigrationFailure: true
|
||||
)
|
||||
|
||||
dataStack.beginSynchronous { (transaction) -> Void in
|
||||
|
||||
transaction.deleteAll(From<UserAccount>(johnConfiguration))
|
||||
transaction.deleteAll(From<UserAccount>(janeConfiguration))
|
||||
transaction.deleteAll(From(UserAccount))
|
||||
|
||||
let account1 = transaction.create(Into<UserAccount>(johnConfiguration))
|
||||
let account1 = transaction.create(Into<MaleAccount>(maleConfiguration))
|
||||
account1.accountType = "Twitter"
|
||||
account1.name = "#johnsmith_hcd"
|
||||
account1.friends = 7
|
||||
|
||||
let account2 = transaction.create(Into<UserAccount>(janeConfiguration))
|
||||
let account2 = transaction.create(Into<FemaleAccount>(femaleConfiguration))
|
||||
account2.accountType = "Twitter"
|
||||
account2.name = "#janedoe_hcd"
|
||||
account2.friends = 100
|
||||
@@ -94,14 +92,8 @@ private struct Static {
|
||||
class StackSetupDemoViewController: UITableViewController {
|
||||
|
||||
let accounts = [
|
||||
[
|
||||
Static.facebookStack.fetchOne(From<UserAccount>(Static.johnConfiguration))!,
|
||||
Static.facebookStack.fetchOne(From<UserAccount>(Static.janeConfiguration))!
|
||||
],
|
||||
[
|
||||
Static.twitterStack.fetchOne(From<UserAccount>(Static.johnConfiguration))!,
|
||||
Static.twitterStack.fetchOne(From<UserAccount>(Static.janeConfiguration))!
|
||||
]
|
||||
Static.facebookStack.fetchAll(From(UserAccount)) ?? [],
|
||||
Static.twitterStack.fetchAll(From(UserAccount)) ?? []
|
||||
]
|
||||
|
||||
|
||||
@@ -169,11 +161,11 @@ class StackSetupDemoViewController: UITableViewController {
|
||||
switch section {
|
||||
|
||||
case 0:
|
||||
let count = Static.facebookStack.fetchCount(From(UserAccount)) ?? 0
|
||||
let count = self.accounts[section].count
|
||||
return "Facebook Accounts (\(count) users)"
|
||||
|
||||
case 1:
|
||||
let count = Static.twitterStack.fetchCount(From(UserAccount)) ?? 0
|
||||
let count = self.accounts[section].count
|
||||
return "Twitter Accounts (\(count) users)"
|
||||
|
||||
default:
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
//
|
||||
// TwitterAccount.swift
|
||||
// CoreStoreDemo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2015/05/24.
|
||||
// Copyright (c) 2015 John Rommel Estropia. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import CoreData
|
||||
|
||||
|
||||
// MARK: - TwitterAccount
|
||||
|
||||
class TwitterAccount: UserAccount { }
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="7701" systemVersion="14D136" minimumToolsVersion="Xcode 4.3" macOSVersion="Automatic" iOSVersion="Automatic">
|
||||
<entity name="FemaleAccount" representedClassName="CoreStoreDemo.FemaleAccount" parentEntity="UserAccount" syncable="YES"/>
|
||||
<entity name="MaleAccount" representedClassName="CoreStoreDemo.MaleAccount" parentEntity="UserAccount" syncable="YES"/>
|
||||
<entity name="UserAccount" representedClassName="CoreStoreDemo.UserAccount" isAbstract="YES" syncable="YES">
|
||||
<attribute name="accountType" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="friends" optional="YES" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
|
||||
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
|
||||
</entity>
|
||||
<configuration name="FemaleAccounts">
|
||||
<memberEntity name="FemaleAccount"/>
|
||||
<memberEntity name="UserAccount"/>
|
||||
</configuration>
|
||||
<configuration name="MaleAccounts">
|
||||
<memberEntity name="MaleAccount"/>
|
||||
<memberEntity name="UserAccount"/>
|
||||
</configuration>
|
||||
<elements>
|
||||
<element name="UserAccount" positionX="-63" positionY="-18" width="128" height="90"/>
|
||||
<element name="MaleAccount" positionX="-54" positionY="18" width="128" height="45"/>
|
||||
<element name="FemaleAccount" positionX="-36" positionY="27" width="128" height="45"/>
|
||||
</elements>
|
||||
</model>
|
||||
@@ -18,7 +18,7 @@ private struct Static {
|
||||
|
||||
static let placeController: ManagedObjectController<Place> = {
|
||||
|
||||
CoreStore.addSQLiteStore(
|
||||
CoreStore.addSQLiteStoreAndWait(
|
||||
"PlaceDemo.sqlite",
|
||||
configuration: "TransactionsDemo",
|
||||
resetStoreOnMigrationFailure: true
|
||||
@@ -77,8 +77,8 @@ class TransactionsDemoViewController: UIViewController, MKMapViewDelegate, Manag
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
let alert = UIAlertController(
|
||||
title: "Observers Demo",
|
||||
message: "This demo shows how to use the 3 types of transactions to save updates: synchronous, asynchronous, and detached. Long-tap on the map to change the pin location.",
|
||||
title: "Transactions Demo",
|
||||
message: "This demo shows how to use the 3 types of transactions to save updates: synchronous, asynchronous, and detached.\n\nTap and hold on the map to change the pin location.",
|
||||
preferredStyle: .Alert
|
||||
)
|
||||
alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
|
||||
|
||||
@@ -47,7 +47,7 @@ class CoreStoreTests: XCTestCase {
|
||||
CoreStore.defaultStack = stack
|
||||
XCTAssert(CoreStore.defaultStack === stack, "CoreStore.defaultStack === stack")
|
||||
|
||||
switch stack.addSQLiteStore("ConfigStore1.sqlite", configuration: "Config1", resetStoreOnMigrationFailure: true){
|
||||
switch stack.addSQLiteStoreAndWait("ConfigStore1.sqlite", configuration: "Config1", resetStoreOnMigrationFailure: true){
|
||||
|
||||
case .Failure(let error):
|
||||
XCTFail(error.description)
|
||||
@@ -56,7 +56,7 @@ class CoreStoreTests: XCTestCase {
|
||||
break
|
||||
}
|
||||
|
||||
switch stack.addSQLiteStore("ConfigStore2.sqlite", configuration: "Config2", resetStoreOnMigrationFailure: true){
|
||||
switch stack.addSQLiteStoreAndWait("ConfigStore2.sqlite", configuration: "Config2", resetStoreOnMigrationFailure: true){
|
||||
|
||||
case .Failure(let error):
|
||||
XCTFail(error.description)
|
||||
|
||||
16
README.md
16
README.md
@@ -2,6 +2,7 @@
|
||||
[](http://cocoadocs.org/docsets/CoreStore)
|
||||
[](http://cocoadocs.org/docsets/CoreStore)
|
||||
[](https://raw.githubusercontent.com/JohnEstropia/CoreStore/master/LICENSE)
|
||||
[](https://github.com/Carthage/Carthage)
|
||||
|
||||
Simple, elegant, and smart Core Data programming with Swift
|
||||
(Swift, iOS 8+)
|
||||
@@ -25,7 +26,7 @@ Simple, elegant, and smart Core Data programming with Swift
|
||||
|
||||
Quick-setup:
|
||||
```swift
|
||||
CoreStore.addSQLiteStore("MyStore.sqlite")
|
||||
CoreStore.addSQLiteStoreAndWait("MyStore.sqlite")
|
||||
```
|
||||
|
||||
Simple transactions:
|
||||
@@ -107,7 +108,7 @@ This allows for a butter-smooth main thread, while still taking advantage of saf
|
||||
## <a id="setup"></a>Setting up
|
||||
The simplest way to initialize CoreStore is to add a default store to the default stack:
|
||||
```swift
|
||||
CoreStore.addSQLiteStore()
|
||||
CoreStore.addSQLiteStoreAndWait()
|
||||
```
|
||||
This one-liner does the following:
|
||||
- Triggers the lazy-initialization of `CoreStore.defaultStack` with a default `DataStack`
|
||||
@@ -126,7 +127,7 @@ case .Failure(let error): // error is an NSError instance
|
||||
println("Failed creating an in-memory store with error: \(error.description)"
|
||||
}
|
||||
|
||||
switch dataStack.addSQLiteStore(
|
||||
switch dataStack.addSQLiteStoreAndWait(
|
||||
fileURL: sqliteFileURL, // set the target file URL for the sqlite file
|
||||
configuration: "Config2", // use entities from the "Config2" configuration in the .xcdatamodeld file
|
||||
automigrating: true, // automatically run lightweight migrations or entity policy migrations when needed
|
||||
@@ -146,7 +147,7 @@ class MyViewController: UIViewController {
|
||||
let dataStack = DataStack(modelName: "MyModel")
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
self.dataStack.addSQLiteStore()
|
||||
self.dataStack.addSQLiteStoreAndWait()
|
||||
}
|
||||
func methodToBeCalledLaterOn() {
|
||||
let objects = self.dataStack.fetchAll(From(MyEntity))
|
||||
@@ -159,7 +160,7 @@ The difference is when you set the stack as the `CoreStore.defaultStack`, you ca
|
||||
class MyViewController: UIViewController {
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
CoreStore.addSQLiteStore()
|
||||
CoreStore.addSQLiteStoreAndWait()
|
||||
}
|
||||
func methodToBeCalledLaterOn() {
|
||||
let objects = CoreStore.fetchAll(From(MyEntity))
|
||||
@@ -757,6 +758,11 @@ pod 'CoreStore'
|
||||
```
|
||||
This installs CoreStore as a framework. Declare `import CoreStore` in your swift file to use the library.
|
||||
|
||||
### Install with Carthage
|
||||
```
|
||||
github "JohnEstropia/CoreStore" >= 0.2.1
|
||||
```
|
||||
|
||||
### Install as Git Submodule
|
||||
```
|
||||
git submodule add https://github.com/JohnEstropia/CoreStore.git <destination directory>
|
||||
|
||||
Reference in New Issue
Block a user