-
-
Save AlexNachbaur/922496 to your computer and use it in GitHub Desktop.
// DataManager.h | |
#import <Foundation/Foundation.h> | |
#import <CoreData/CoreData.h> | |
extern NSString * const DataManagerDidSaveNotification; | |
extern NSString * const DataManagerDidSaveFailedNotification; | |
@interface DataManager : NSObject { | |
} | |
@property (nonatomic, readonly, retain) NSManagedObjectModel *objectModel; | |
@property (nonatomic, readonly, retain) NSManagedObjectContext *mainObjectContext; | |
@property (nonatomic, readonly, retain) NSPersistentStoreCoordinator *persistentStoreCoordinator; | |
+ (DataManager*)sharedInstance; | |
- (BOOL)save; | |
- (NSManagedObjectContext*)managedObjectContext; | |
@end |
// DataManager.m | |
#import "DataManager.h" | |
NSString * const DataManagerDidSaveNotification = @"DataManagerDidSaveNotification"; | |
NSString * const DataManagerDidSaveFailedNotification = @"DataManagerDidSaveFailedNotification"; | |
@interface DataManager () | |
- (NSString*)sharedDocumentsPath; | |
@end | |
@implementation DataManager | |
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator; | |
@synthesize mainObjectContext = _mainObjectContext; | |
@synthesize objectModel = _objectModel; | |
NSString * const kDataManagerBundleName = @"MyApp"; | |
NSString * const kDataManagerModelName = @"MyApp"; | |
NSString * const kDataManagerSQLiteName = @"MyApp.sqlite"; | |
+ (DataManager*)sharedInstance { | |
static dispatch_once_t pred; | |
static DataManager *sharedInstance = nil; | |
dispatch_once(&pred, ^{ sharedInstance = [[self alloc] init]; }); | |
return sharedInstance; | |
} | |
- (void)dealloc { | |
[self save]; | |
[_persistentStoreCoordinator release]; | |
[_mainObjectContext release]; | |
[_objectModel release]; | |
[super dealloc]; | |
} | |
- (NSManagedObjectModel*)objectModel { | |
if (_objectModel) | |
return _objectModel; | |
NSBundle *bundle = [NSBundle mainBundle]; | |
if (kDataManagerBundleName) { | |
NSString *bundlePath = [[NSBundle mainBundle] pathForResource:kDataManagerBundleName ofType:@"bundle"]; | |
bundle = [NSBundle bundleWithPath:bundlePath]; | |
} | |
NSString *modelPath = [bundle pathForResource:kDataManagerModelName ofType:@"momd"]; | |
_objectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:[NSURL fileURLWithPath:modelPath]]; | |
return _objectModel; | |
} | |
- (NSPersistentStoreCoordinator*)persistentStoreCoordinator { | |
if (_persistentStoreCoordinator) | |
return _persistentStoreCoordinator; | |
// Get the paths to the SQLite file | |
NSString *storePath = [[self sharedDocumentsPath] stringByAppendingPathComponent:kDataManagerSQLiteName]; | |
NSURL *storeURL = [NSURL fileURLWithPath:storePath]; | |
// Define the Core Data version migration options | |
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: | |
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, | |
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, | |
nil]; | |
// Attempt to load the persistent store | |
NSError *error = nil; | |
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.objectModel]; | |
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType | |
configuration:nil | |
URL:storeURL | |
options:options | |
error:&error]) { | |
NSLog(@"Fatal error while creating persistent store: %@", error); | |
abort(); | |
} | |
return _persistentStoreCoordinator; | |
} | |
- (NSManagedObjectContext*)mainObjectContext { | |
if (_mainObjectContext) | |
return _mainObjectContext; | |
// Create the main context only on the main thread | |
if (![NSThread isMainThread]) { | |
[self performSelectorOnMainThread:@selector(mainObjectContext) | |
withObject:nil | |
waitUntilDone:YES]; | |
return _mainObjectContext; | |
} | |
_mainObjectContext = [[NSManagedObjectContext alloc] init]; | |
[_mainObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator]; | |
return _mainObjectContext; | |
} | |
- (BOOL)save { | |
if (![self.mainObjectContext hasChanges]) | |
return YES; | |
NSError *error = nil; | |
if (![self.mainObjectContext save:&error]) { | |
NSLog(@"Error while saving: %@\n%@", [error localizedDescription], [error userInfo]); | |
[[NSNotificationCenter defaultCenter] postNotificationName:DataManagerDidSaveFailedNotification | |
object:error]; | |
return NO; | |
} | |
[[NSNotificationCenter defaultCenter] postNotificationName:DataManagerDidSaveNotification object:nil]; | |
return YES; | |
} | |
- (NSString*)sharedDocumentsPath { | |
static NSString *SharedDocumentsPath = nil; | |
if (SharedDocumentsPath) | |
return SharedDocumentsPath; | |
// Compose a path to the <Library>/Database directory | |
NSString *libraryPath = [[NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES) objectAtIndex:0] retain]; | |
SharedDocumentsPath = [[libraryPath stringByAppendingPathComponent:@"Database"] retain]; | |
// Ensure the database directory exists | |
NSFileManager *manager = [NSFileManager defaultManager]; | |
BOOL isDirectory; | |
if (![manager fileExistsAtPath:SharedDocumentsPath isDirectory:&isDirectory] || !isDirectory) { | |
NSError *error = nil; | |
NSDictionary *attr = [NSDictionary dictionaryWithObject:NSFileProtectionComplete | |
forKey:NSFileProtectionKey]; | |
[manager createDirectoryAtPath:SharedDocumentsPath | |
withIntermediateDirectories:YES | |
attributes:attr | |
error:&error]; | |
if (error) | |
NSLog(@"Error creating directory path: %@", [error localizedDescription]); | |
} | |
return SharedDocumentsPath; | |
} | |
- (NSManagedObjectContext*)managedObjectContext { | |
NSManagedObjectContext *ctx = [[[NSManagedObjectContext alloc] init] autorelease]; | |
[ctx setPersistentStoreCoordinator:self.persistentStoreCoordinator]; | |
return ctx; | |
} | |
@end |
What is the best way to implement undoManager?
@NachoMan, thanks for posting this and @rojotek for the update.
I'd like to echo @odowd's last question, what's the reasoning behind hardcoding the app bundle name? Seems like the mainBundle would be adequate. (I have to comment out L#46-50 in the .m file, or it doesn't find the url in the bundle and throws an exception, it's not finding my bundle via the name.)
No reason really, you can just as easily make it programmatic by introspecting the NSBundle object and fetching the target name.
@NachoMan thanks for this great helper class. Got everything to work, though as @pillbaker said I used the [NSBundle mainBundle] to get the momd. I have a question regarding
-(NSManagedObjectContext*)managedObjectContext method. What is it's use? Initially I though that is the NSManagedObjectContext I should have used but later noticed it is the mainObjectContext I should be using.
Hey - just did a fork to remove the "retain" and "dealloc" methods which aren't ARC friendly.
https://gist.github.com/2362546