I created a Single View Application in iOS that also incorporates Core Data. I moved my .xcdatamodel file from another application and put in to the one I am working on now, and I am having issues. What I have done is cut and paste the code from the previous application and placed it in my AppDelegate.h/m files:
@interface DBAppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
- (void)saveContext;
- (NSURL *)applicationDocumentsDirectory;
@end
and my .m file:
@implementation DBAppDelegate
@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
//the line below is what is causing an error
DBViewController *controller = (DBViewController *)navigationController.topViewController;
controller.managedObjectContext = self.managedObjectContext;
return YES;
}
Within my .m file, I also included the boiler plate code for Core Data that was also in my previous application which I have not posted. In my new application, what I am doing is that I have created an access layer, which also provides a Singleton instance to access this layer. It is in this class where I do my CRUD operations, and have declared the following properties in the .h file:
@property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
@property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
At the moment, I am getting the following error:
"Property 'managedObjectContext' not found on object of type "DBViewController". What I would like to do is initialize the managedObjectContext inside my method that allows for the creation of a Singleton instance:
static DB *sharedSingleton = nil;
+ (DB *) sharedInstance {
if (sharedSingleton == nil) {
sharedSingleton = [[super alloc] init];
}
return sharedSingleton;
}
What am I doing wrong? I realize I don't declare a managedObjectContext object in my DBViewController, but what do I put in place of this line? I figure it would be something with respect to my Singleton class, but I honestly don't have a clue here.
What you are trying to do is often called a "data store" singleton, and it's a good design pattern to use. What I do in my applications is have a singleton class named DataStore
, you can call it whatever you wish, with a class method:
+ (id)sharedStore{
static DataStore *sharedStore = nil;
if (!sharedStore) {
sharedStore = [[self alloc] init];
}
return sharedStore;
}
Whenever I need access to the resources provided by the datastore, I do:
Datastore *ds = [Datastore sharedStore];
To provide access to Core Data, I have a data store method:
+ (NSManagedObjectContext*)managedObjectContext{
static NSManagedObjectContext *context = nil;
if(context){
return context;
}
NSPersistentStoreCoordinator *coordinator = nil;
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Model" withExtension:@"momd"];
NSManagedObjectModel *objectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
if (!coordinator) {
coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:objectModel];
}
if(!coordinator){
return nil;
}
NSString *storePath = [[self documentsDirectoryPath] stringByAppendingPathComponent:@"datastore.sqlite"];
NSURL *storeURL = [NSURL URLWithString:storePath];
NSError *error;
if (![coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:NULL error:&error])
{
NSLog(@"Database error: %@", error);
// if you make changes to your model and a database already exists in the app
// you'll get a NSInternalInconsistencyException exception. When the model is updated
// the databasefile must be removed. Remove the database here because it's easy.
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtURL:storeURL error:nil];
//try to add the persistant store one more time. If it still fails then abort
if (![coordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:NULL error:&error])
return nil;
}
context = [[NSManagedObjectContext alloc] init];
[context setPersistentStoreCoordinator:coordinator];
[context setUndoManager:nil];
return context;
}
This method returns nil
if an NSManagedObjectContext
couldn't be created. This way you only need to do:
NSManagedObjectContext *context = [[DataStore sharedStore] managedObjectContext];
whenever you need to use Core Data. This can be done once in viewDidLoad
.
Edit:
The managedObjectContext
method uses the method below to find the documents directory:
+ (NSString *)documentsDirectoryPath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
return basePath;
}