Improved contexts stack implementation

This commit is contained in:
Pedro Piñera 2014-08-05 01:11:13 +02:00
parent d111aae2f2
commit a92236a19d
4 changed files with 135 additions and 114 deletions

View File

@ -30,25 +30,30 @@ class SugarRecord {
// Initialize Database
class func setupCoreDataStack (automigrating: Bool?, databaseName: String?) -> () {
// Checking the coordinator doesn't exist
if let psc = NSPersistentStoreCoordinator.defaultPersistentStoreCoordinator(){}
else {
var psc: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator.defaultPersistentStoreCoordinator()
if psc == nil {
return
}
// Initializing persistentStoreCoordinator
var psc: NSPersistentStoreCoordinator
if let dbName = databaseName {
psc = NSPersistentStoreCoordinator.newCoordinator(dbName, automigrating: automigrating)
if databaseName != nil {
psc = NSPersistentStoreCoordinator.newCoordinator(databaseName!, automigrating: automigrating)
}
else {
psc = NSPersistentStoreCoordinator.newCoordinator(self.defaultDatabaseName(), automigrating: automigrating)
}
NSPersistentStoreCoordinator.setDefaultPersistentStoreCoordinator(psc)
// Setting as default persistent store coordinator
NSPersistentStoreCoordinator.setDefaultPersistentStoreCoordinator(psc!)
// Initialize stack
NSManagedObjectContext.initializeContextsStack(psc!)
}
// CleanUp
class func cleanUp () -> () {
NSManagedObjectContext.cleanUp()
}
// Returns current stack information
@ -94,30 +99,109 @@ extension NSManagedObjectContext {
return Static.rootSavingContext
}
// Root Saving Context Setter
class func setRootSavingContext(context: NSManagedObjectContext?) {
Static.rootSavingContext = context
}
// Default Context Getter
class func defaultContext() -> (NSManagedObjectContext?) {
return Static.defaultContext
}
// Returns a new context with default context as parent
class func newContext (parentContext: NSManagedObjectContext?) -> (NSManagedObjectContext) {
var context: NSManagedObjectContext = NSManagedObjectContext()
context.parentContext = self.defaultContext()!
return context
// Default Context Setter
class func setDefaultContext(context: NSManagedObjectContext?) {
Static.defaultContext = context
}
// Returns a new context with a given context as a parent
class func newContextWithPersistentStoreCoordinator(persistentStoreCoordinator: NSPersistentStoreCoordinator) -> (NSManagedObjectContext){
return self.newContext(nil, persistentStoreCoordinator: persistentStoreCoordinator)
}
// Returns a new context with a given context as a parent
class func newContextWithParentContext(parentContext: NSManagedObjectContext) -> (NSManagedObjectContext){
return self.newContext(parentContext, persistentStoreCoordinator: nil)
}
// Returns a new context with a parent context or persistentStoreCoordinator
class func newContext (parentContext: NSManagedObjectContext?, persistentStoreCoordinator: NSPersistentStoreCoordinator?) -> (NSManagedObjectContext) {
var newContext: NSManagedObjectContext?
if parentContext != nil {
newContext = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)
newContext?.parentContext = self.defaultContext()!
}
else if persistentStoreCoordinator != nil {
newContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
newContext?.persistentStoreCoordinator = persistentStoreCoordinator
}
else {
assert(true, "SUGAR-RECORD: Either parentContext or persistentStoreCoordinator has to be passed")
}
println("SUGAR-RECORD: Created new context - \(newContext)")
return newContext!
}
// Initialize default contexts stack
class func initializeContextsStack (persistentStoreCoordinator: NSPersistentStoreCoordinator) {
var rootContext: NSManagedObjectContext = self.newContext(nil, persistentStoreCoordinator: persistentStoreCoordinator)
self.setRootSavingContext(rootSavingContext())
var defaultContext: NSManagedObjectContext = self.newContext(rootContext, persistentStoreCoordinator: nil)
}
// CleanUp
class func cleanUp () -> () {
self.setRootSavingContext(nil)
self.setDefaultContext(nil)
}
}
//MARK - NSManagedObject Extension
extension NSManagedObjectModel {
// Static variables
struct Static {
static var defaultManagedObjectModel: NSManagedObjectModel? = nil
}
class func setDefaultManagedObjectModel(objectModel: NSManagedObjectModel) {
Static.defaultManagedObjectModel = objectModel
}
class func defaultManagedObjectModel() -> (defaultManagedObjectModel: NSManagedObjectModel?) {
var currentModel: NSManagedObjectModel? = Static.defaultManagedObjectModel
if currentModel == nil {
currentModel = self.mergedModelFromBundles(nil)
self.setDefaultManagedObjectModel(currentModel!)
}
return currentModel
}
}
/*
if (defaultManagedObjectModel_ == nil && [MagicalRecord shouldAutoCreateManagedObjectModel])
{
[self MR_setDefaultManagedObjectModel:[self MR_mergedObjectModelFromMainBundle]];
}
return defaultManagedObjectModel_;
+ (NSManagedObjectModel *) MR_mergedObjectModelFromMainBundle;
{
return [self mergedModelFromBundles:nil];
}
*/
// MARK - NSManagedObject Extension
extension NSManagedObject {
class func defaultManagedObject () -> (NSManagedObject?) {
return nil;
}
class func filter (context: NSManagedObjectContext?, predicate: NSPredicate) -> (NSArray) {
return nil
}
@ -126,12 +210,10 @@ extension NSManagedObject {
* @param NSPredicate To filter fetch results
* @return Int with the count
*/
class func count(context: NSManagedObjectContext?, predicate: NSPredicate) -> (count: Int) {
class func count(context: NSManagedObjectContext?, predicate: NSPredicate) -> (count: Int?) {
return self.filter(context, predicate: predicate).count
return nil
}
}
@ -151,10 +233,24 @@ extension NSPersistentStoreCoordinator {
// Coordinator initializer
class func newCoordinator (databaseName: String, automigrating: Bool?) -> (NSPersistentStoreCoordinator) {
class func newCoordinator (databaseName: String, automigrating: Bool?) -> (NSPersistentStoreCoordinator?) {
var model: NSManagedObjectModel = NSManagedObjectModel.defaultManagedObjectModel()
return nil
}
/*NSManagedObjectModel *model = [NSManagedObjectModel MR_defaultManagedObjectModel];
NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
[coordinator MR_addAutoMigratingSqliteStoreNamed:storeFileName];
//HACK: lame solution to fix automigration error "Migration failed after first pass"
if ([[coordinator persistentStores] count] == 0)
{
[coordinator performSelector:@selector(MR_addAutoMigratingSqliteStoreNamed:) withObject:storeFileName afterDelay:0.5];
}*/
}

View File

@ -15,6 +15,7 @@
3DBC55F4198E826E00268EB3 /* SugarRecordTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DBC55F3198E826E00268EB3 /* SugarRecordTests.swift */; };
3DBC55FF198E82F500268EB3 /* SugarRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DBC55FE198E82F500268EB3 /* SugarRecord.swift */; };
3DBC5603198E844B00268EB3 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DBC5602198E844B00268EB3 /* CoreData.framework */; };
3DD010AF1990379D00673854 /* SugarRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DBC55FE198E82F500268EB3 /* SugarRecord.swift */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -64,7 +65,6 @@
3DBC55CF198E826E00268EB3 = {
isa = PBXGroup;
children = (
3DBC5602198E844B00268EB3 /* CoreData.framework */,
3DBC55DA198E826E00268EB3 /* SugarRecord */,
3DBC55F0198E826E00268EB3 /* SugarRecordTests */,
3DBC55D9198E826E00268EB3 /* Products */,
@ -83,6 +83,7 @@
3DBC55DA198E826E00268EB3 /* SugarRecord */ = {
isa = PBXGroup;
children = (
3DD010AE1990378200673854 /* Frameworks */,
3DBC55FD198E82E300268EB3 /* SugarRecord */,
3DBC55DD198E826E00268EB3 /* AppDelegate.swift */,
3DBC55E2198E826E00268EB3 /* ViewController.swift */,
@ -128,6 +129,14 @@
path = ../../SugarRecord;
sourceTree = "<group>";
};
3DD010AE1990378200673854 /* Frameworks */ = {
isa = PBXGroup;
children = (
3DBC5602198E844B00268EB3 /* CoreData.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -238,6 +247,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
3DD010AF1990379D00673854 /* SugarRecord.swift in Sources */,
3DBC55F4198E826E00268EB3 /* SugarRecordTests.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@ -14,9 +14,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
// Override point for customization after application launch.
var name: String! = nil
println(name)
return true
}
@ -41,95 +42,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func applicationWillTerminate(application: UIApplication!) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
// Saves changes in the application's managed object context before the application terminates.
self.saveContext()
}
func saveContext () {
var error: NSError? = nil
let managedObjectContext = self.managedObjectContext
if managedObjectContext != nil {
if managedObjectContext.hasChanges && !managedObjectContext.save(&error) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
//println("Unresolved error \(error), \(error.userInfo)")
abort()
}
}
}
// #pragma mark - Core Data stack
// Returns the managed object context for the application.
// If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
var managedObjectContext: NSManagedObjectContext {
if !_managedObjectContext {
let coordinator = self.persistentStoreCoordinator
if coordinator != nil {
_managedObjectContext = NSManagedObjectContext()
_managedObjectContext!.persistentStoreCoordinator = coordinator
}
}
return _managedObjectContext!
}
var _managedObjectContext: NSManagedObjectContext? = nil
// Returns the managed object model for the application.
// If the model doesn't already exist, it is created from the application's model.
var managedObjectModel: NSManagedObjectModel {
if !_managedObjectModel {
let modelURL = NSBundle.mainBundle().URLForResource("SugarRecord", withExtension: "momd")
_managedObjectModel = NSManagedObjectModel(contentsOfURL: modelURL)
}
return _managedObjectModel!
}
var _managedObjectModel: NSManagedObjectModel? = nil
// Returns the persistent store coordinator for the application.
// If the coordinator doesn't already exist, it is created and the application's store added to it.
var persistentStoreCoordinator: NSPersistentStoreCoordinator {
if !_persistentStoreCoordinator {
let storeURL = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SugarRecord.sqlite")
var error: NSError? = nil
_persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
if _persistentStoreCoordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: nil, error: &error) == nil {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
Typical reasons for an error here include:
* The persistent store is not accessible;
* The schema for the persistent store is incompatible with current managed object model.
Check the error message to determine what the actual problem was.
If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.
If you encounter schema incompatibility errors during development, you can reduce their frequency by:
* Simply deleting the existing store:
NSFileManager.defaultManager().removeItemAtURL(storeURL, error: nil)
* Performing automatic lightweight migration by passing the following dictionary as the options parameter:
[NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true]
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
*/
//println("Unresolved error \(error), \(error!.userInfo)")
abort()
}
}
return _persistentStoreCoordinator!
}
var _persistentStoreCoordinator: NSPersistentStoreCoordinator? = nil
// #pragma mark - Application's Documents directory
// Returns the URL to the application's Documents directory.
var applicationDocumentsDirectory: NSURL {
let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
return urls[urls.count-1] as NSURL
}
}

View File

@ -8,19 +8,23 @@
import UIKit
import XCTest
import SugarRecord
class SugarRecordTests: XCTestCase {
class SugarRecordSetupTests: XCTestCase {
var sugarRecord: SugarRecord?
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
sugarRecord = SugarRecord()
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testExample() {
// This is an example of a functional test case.
XCTAssert(true, "Pass")
@ -32,5 +36,4 @@ class SugarRecordTests: XCTestCase {
// Put the code you want to measure the time of here.
}
}
}