CoreData NSManagedObjectContext not found - objective-c

New to iOS development. I am trying to use the core data stack in a sample app, which fetches data over network and simply updates the UI. Whilst creating the project, the "Use Core Data" checkbox was ticked which generates bunch of boilerplate code. However, on XCode 8.2.1, the I only see the NSPersistentContainer implementation within the AppDelegate.m file.
- (NSPersistentContainer *)persistentContainer {
// The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.
#synchronized (self) {
if (_persistentContainer == nil) {
_persistentContainer = [[NSPersistentContainer alloc] initWithName:#"ergast_coredata_objc"];
[_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
if (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 parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
NSLog(#"Unresolved error %#, %#", error, error.userInfo);
abort();
}
}];
}
}
return _persistentContainer;
}
There is no boilerplate code for the NSManagedObjectContext as most of the tutorials would have you believe.
Hence, the following block within the ViewController.m class fails with a Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[AppDelegate managedObjectContext]: unrecognized selector sent to instance
-(NSArray *)getSeasonsList{
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"SeasonData"];
NSError *error = nil;
NSArray *results = [[self getManagedObjectContext] executeFetchRequest:request error:&error];
if (!results) {
NSLog(#"Error fetching objects: %#\n%#", [error localizedDescription], [error userInfo]);
abort();
}
return results;
}
- (NSManagedObjectContext *)getManagedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
context = [delegate managedObjectContext];
return context;
}
Tried looking online but most of the tutorials are Swift based it seems. What am i missing here? Is the developer supposed to provide the implementation for the NSManagedObjectContext? Would be much appreciated if someone can provide with an Objective-c based sample code.
Thanks!

See in saveContext method
pragma mark - Core Data Saving support
- (void)saveContext {
// OBSERVE HERE
NSManagedObjectContext *context = self.persistentContainer.viewContext;
NSError *error = nil;
if ([context hasChanges] && ![context 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.
NSLog(#"Unresolved error %#, %#", error, error.userInfo);
abort();
}
}
Whenever you need NSManagedObjectContext instance, access like this
NSManagedObjectContext *context = self.persistentContainer.viewContext;
self.persistentContainer OR classObject.persistentContainer

Modify the "getManagedObjectContext" method as below
- (NSManagedObjectContext *)getManagedObjectContext {
AppDelegate *delegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [[delegate persistentContainer] viewContext];
return context;
}
I didn't tested this, but hope this will work

I have a category for appdelegate that was included in one of the old Stanford CS193P that uses objective-c. Some of it might be deprecated, though. Also check out https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/InitializingtheCoreDataStack.html#//apple_ref/doc/uid/TP40001075-CH4-SW1 has objective-c sample. Post back if that helps.
//
// PhotomaniaAppDelegate+MOC.m
// Photomania
//
// This code comes from the Xcode template for Master-Detail application.
#import "PhotomaniaAppDelegate+MOC.h"
#import <CoreData/CoreData.h>
#implementation PhotomaniaAppDelegate (MOC)
#pragma mark - Core Data
- (void)saveContext:(NSManagedObjectContext *)managedObjectContext
{
NSError *error = nil;
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.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
}
// 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.
- (NSManagedObjectContext *)createMainQueueManagedObjectContext
{
NSManagedObjectContext *managedObjectContext = nil;
NSPersistentStoreCoordinator *coordinator = [self createPersistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return managedObjectContext;
}
// Returns the managed object model for the application.
// If the model doesn't already exist, it is created from the application's model.
- (NSManagedObjectModel *)createManagedObjectModel
{
NSManagedObjectModel *managedObjectModel = nil;
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"Photomania" withExtension:#"momd"];
managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return managedObjectModel;
}
// 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.
- (NSPersistentStoreCoordinator *)createPersistentStoreCoordinator
{
NSPersistentStoreCoordinator *persistentStoreCoordinator = nil;
NSManagedObjectModel *managedObjectModel = [self createManagedObjectModel];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"MOC.sqlite"];
NSError *error = nil;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:managedObjectModel];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&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.
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:#YES, NSInferMappingModelAutomaticallyOption:#YES}
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return persistentStoreCoordinator;
}
// Returns the URL to the application's Documents directory
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
#end
Also, check out this project https://github.com/m2mtech/photomania-2013-14/tree/master/Photomania/CoreDataTableViewController/MOC More info how Core Data was used with this implementation.

Related

Core Data isn't being reset when I close the calling class - how can I reset it?

This is a question that appears to have been answered many times on Stack Overflow - but still it doesn't work for my use-case. Core Data mostly works fine. The problem comes when closing the document - at that point I need the Core Data to be reset, ready for the next Document to be loaded. What actually happens is that the next Document to be loaded gets loaded with all of its data, and all of the previous Documents data - and it doesn't reset until the Application is quit and reopened again.
I have an NSDocument based application which can load many different document types. Each document type is described in its own Class. Foo, for example, might be a really simple document type, small, text based, no problem to handle so it doesn't need a complex class to load it. Bar, on the other hand, is a vast complicated database many GB in size - and it doesn't make sense to load it all into memory.
My Bar class uses Core Data - it's the only one that needs to, and therefore the only one which contains this logic. I mention this because nearly every description on how to use Core Data puts the Core Data code in App Delegate - there might be a good reason for this!
In my Bar header I have my Core Data set up as follows:
#property (nonatomic, strong, readonly) NSManagedObjectModel *managedObjectModel;
#property (nonatomic, strong) NSPersistentStoreCoordinator *persistentStoreCoordinator;
#property (nonatomic, strong, readonly) NSManagedObjectContext *managedObjectContext;
#property (nonatomic, strong, readonly) NSDate *readStart;
And in my Bar .m I have the following:
- (NSURL *)dataStoreURL {
NSString *docDir = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0];
//NSString* filename = [NSString stringWithFormat:#"%#.sql",[StringWangers generateUUIDString]];
NSString* filename = #"datastore.sql";
return [NSURL fileURLWithPath:[docDir stringByAppendingPathComponent:filename]];
}
- (NSManagedObjectModel *)managedObjectModel {
if (_managedObjectModel) {
return _managedObjectModel;
}
_managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (_persistentStoreCoordinator) {
return _persistentStoreCoordinator;
}
[NSFileManager.defaultManager removeItemAtURL:self.dataStoreURL error:nil]; // this isn't supposed to be persistent - clear out old crap
NSError *error = nil;
NSDictionary *options = #{NSMigratePersistentStoresAutomaticallyOption: #(YES), NSInferMappingModelAutomaticallyOption: #(YES)};
_persistentStoreCoordinator = [NSPersistentStoreCoordinator.alloc initWithManagedObjectModel:self.managedObjectModel];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:self.dataStoreURL
options:options
error:&error]) {
NSLog(#"Unresolved Core Data error with persistentStoreCoordinator: %#, %#", error, [error userInfo]);
}
return _persistentStoreCoordinator;
}
- (NSManagedObjectContext *)managedObjectContext {
if (_managedObjectContext) {
return _managedObjectContext;
}
if ([self persistentStoreCoordinator]) {
_managedObjectContext = [NSManagedObjectContext.alloc initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator:[self persistentStoreCoordinator]];
}
return _managedObjectContext;
}
I've tried many things to delete this pesky data - including, belt and braces, everything (which I really don't like doing because I'd like to understand what's going on - but I was desperate!) - this is the 'everything' stateā€¦
-(void)deinitialise {
#try {
NSLog(#"Deleting old core storage");
NSArray *allEntities = self.managedObjectModel.entities;
for (NSEntityDescription *entityDescription in allEntities) {
NSFetchRequest *fetchRequest = NSFetchRequest.new;
[fetchRequest setEntity:entityDescription];
fetchRequest.includesPropertyValues = NO;
fetchRequest.includesSubentities = NO;
NSLog(#"%#",fetchRequest);
NSError *error = nil;
NSArray *items;
if (self.managedObjectContext &&
fetchRequest &&
([fetchRequest.sortDescriptors isKindOfClass:NSArray.class] && fetchRequest.sortDescriptors.count > 0) &&
fetchRequest.predicate) {
items = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
}
if (error) {
NSLog(#"Error requesting items from Core Data: %#", error.localizedDescription);
}
for (NSManagedObject *managedObject in items) {
[self.managedObjectContext deleteObject:managedObject];
[self.managedObjectContext save:&error];
if (error) {
NSLog(#"Error deleting items from Core Data: %#", error.localizedDescription);
}
}
}
}
#catch (NSException *exception) {
NSLog(#"Error deleting persistent storage - Exception: %#", exception);
}
NSError *error = nil;
NSArray* persistentStoreArray = self.persistentStoreCoordinator.persistentStores;
for (id store in persistentStoreArray) {
[self.persistentStoreCoordinator removePersistentStore:store error:&error];
if (error) {
NSLog(#"Error Removing Persistent Store: %#", error.localizedDescription);
}
NSString* storePath = [store URL].path;
NSLog(#"%#",storePath);
[NSFileManager.defaultManager removeItemAtPath:storePath error:&error];
if (error) {
NSLog(#"Error Deleting Persistent Store: %#", error.localizedDescription);
}
}
self.persistentStoreCoordinator = nil;
}
Interestingly, - (NSPersistentStoreCoordinator *)persistentStoreCoordinator only gets called the first time that my Bar class is called on document load, but every time I call my reinitialise class.
Hopefully this makes sense to someone - 'cos I'm bang out of ideas.
Thank you to everyone who posted suggestions. They were great avenues of investigation - but they all turned out to be incorrect for my particular use-case. In the event, all I had to do was this:
-(void)deinitialise {
[self.managedObjectContext reset];
}
I hope that this might help someone else who has this problem.

NSFetchedResultsController requires a non-nil fetchRequest and managedObjectContext

i am having a problem since days, i tryed all the solutions here in stackoverflow but anyone gives me a solution.
i am using core data and tableviewcontroller.
My CoreDataTableViewController its correct, i downloaded it from timroadnley and u use it in another projects.
Im getting an error : 'An instance of NSFetchedResultsController requires a non-nil fetchRequest and managedObjectContext'
The application loads correctly but when i press to go to the marksTableviewcontroller, it fails.
THE ERROR IS ON THIS LINE:
- (void)setupFetchedResultsController{
// 1 - Decide what Entity you want
NSString *entityName = #"Marks"; // Put your entity name here
NSLog(#"Setting up a Fetched Results Controller for the Entity named %#", entityName);
// 2 - Request that Entity
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entityName];
// 4 - Sort it if you want
request.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"subject"
ascending:YES
selector:#selector(localizedCaseInsensitiveCompare:)]];
// 5 - Fetch it
self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
managedObjectContext:self.managedObjectContext
sectionNameKeyPath:nil
cacheName:nil]; //IN THIS LILE IS THE ERROR, IN "REQUEST"
[self performFetch];
}
THIS IS MY APPDELEGATE:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
marksTVCon.managedObjectContext = self.managedObjectContext;
NSDictionary *defaultsDict = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithBool:YES], #"FirstLaunch", nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:defaultsDict];
NSUserDefaults *sharedDefaults = [NSUserDefaults standardUserDefaults];
if([sharedDefaults boolForKey:#"FirstLaunch"]) {
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"MYAPP" message:#"Thanks for downloading, hope you love our app" delegate:nil cancelButtonTitle:#"Go app" otherButtonTitles:nil, nil];
[message show];
[sharedDefaults setBool:NO forKey:#"FirstLaunch"];
[sharedDefaults synchronize];
}
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// Saves changes in the application's managed object context before the application terminates.
[self saveContext];
}
- (void)saveContext
{
NSError *error = nil;
NSManagedObjectContext *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.
NSLog(#"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.
- (NSManagedObjectContext *)managedObjectContext
{
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return _managedObjectContext;
}
// Returns the managed object model for the application.
// If the model doesn't already exist, it is created from the application's model.
- (NSManagedObjectModel *)managedObjectModel
{
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"MYAPP" withExtension:#"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
// 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.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"MYAPP.sqlite"];
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&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.
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:#YES, NSInferMappingModelAutomaticallyOption:#YES}
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
#pragma mark - Application's Documents directory
// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
#end
If you need to ask for anyother peace of code pliz ask for it, I think the problem is in there, but im not pretty Sure.

How does UIManagedDocument find the default data model file?

I've been following the CS193p's lectures on Core data and I've run into a problem when I'm inserting a new managed object.
The error is:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+entityForName: could not
locate an entity named 'Card' in this model.'
I've created the "Card" entity in my data model file. However I have a feeling it isn't finding the data model file correctly, since removing that file all together give the same error. I'm wondering how I can find out whether it is due the UIManagedDocument object not finding the data model that is causing this error.
Here is what I'm doing in my controller class:
NSURL *docURL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *databaseURL = [docURL URLByAppendingPathComponent:#"Cards Database"];
self.cardsDatabase = [[UIManagedDocument alloc] initWithFileURL:databaseURL];
if (![[NSFileManager defaultManager] fileExistsAtPath:[self.cardsDatabase.fileURL path]]) {
[self.cardsDatabase saveToURL:self.cardsDatabase.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
NSLog(#"Done");
}];
} else if (self.cardsDatabase.documentState == UIDocumentStateClosed) {
NSLog(#"Closed");
[self.cardsDatabase openWithCompletionHandler:^(BOOL success) {
if (success) {
NSLog(#"Opened");
[self addSampleData];
}
}];
} else if (self.cardsDatabase.documentState == UIDocumentStateNormal) {
NSLog(#"Normal");
}
- (void)addSampleData
{
NSManagedObjectContext *context = self.cardsDatabase.managedObjectContext;
[context performBlockAndWait:^{
Card *card = [NSEntityDescription insertNewObjectForEntityForName:#"Card" inManagedObjectContext:context];
card.title = #"Test Title";
}];
[self.cardsDatabase saveToURL:self.cardsDatabase.fileURL forSaveOperation:UIDocumentSaveForOverwriting completionHandler:^(BOOL success) {
NSLog(#"Saved");
}];
}
The error occurs on this line:
Card *card = [NSEntityDescription insertNewObjectForEntityForName:#"Card" inManagedObjectContext:context];
Try resetting the simulator(In device, remove the app), clean the build and run again. That should resolve most of the issues related to 'could not locate entities'.
This kind of issue may happen, when you updated your Core Data model, by changing names of attributes of entities, and then Run it without clean(delete) the app with the older Core Data model from the device. Unless you are planning to use light migration or model mapping, please be aware it may happen whenever you Run the app

Core Data without Master Detail Template

I want to create an iphone application which uses Core Data.
As i understood, only master-detail application template gives me an option to use Core Data. But it creates table view.
What i want to use is view controller not table view controller.
I couldnt use core data with single view application template..
Which way should I follow to overcome this issue?
Thanks.
You should realize that CoreData is a framework that is not bound to any UIKit components like UITableView. You can freely use it in any sort of an application. All you have to do is to create your singleton class that manages CoreData operations and add CoreData.framework to your project.
Here is my DataAccessLayer template:
DataAccessLayer.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface DataAccessLayer : NSObject
#property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
#property (strong, nonatomic) NSManagedObjectModel *managedObjectModel;
#property (strong, nonatomic) NSPersistentStoreCoordinator *storeCoordinator;
+ (DataAccessLayer *)sharedInstance;
- (void)saveContext;
#end
DataAccessLayer.m
#import "DataAccessLayer.h"
#interface DataAccessLayer ()
- (NSURL *)applicationDocumentsDirectory;
#end
#implementation DataAccessLayer
#synthesize storeCoordinator;
#synthesize managedObjectModel;
#synthesize managedObjectContext;
+ (DataAccessLayer *)sharedInstance {
__strong static DataAccessLayer *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[DataAccessLayer alloc] init];
sharedInstance.storeCoordinator = [sharedInstance persistentStoreCoordinator];
sharedInstance.managedObjectContext = [sharedInstance managedObjectContext];
});
return sharedInstance;
}
#pragma mark - Core Data
- (void)saveContext {
#synchronized(self) {
NSError *error = nil;
if (managedObjectContext != nil)
{
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error])
{
NSLog(#"error: %#", error.userInfo);
/*
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. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Oops!"
message:#"Something has gone terribly wrong! You need to reinstall the app in order for it to work properly."
delegate:nil
cancelButtonTitle:#"Close."
otherButtonTitles:nil, nil];
[alert show];
}
}
}
}
#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.
*/
- (NSManagedObjectContext *)managedObjectContext {
if (managedObjectContext != nil)
{
return managedObjectContext;
}
if (storeCoordinator != nil)
{
managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator:storeCoordinator];
}
return managedObjectContext;
}
/**
Returns the managed object model for the application.
If the model doesn't already exist, it is created from the application's model.
*/
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel != nil)
{
return managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"DataModel" withExtension:#"momd"];
managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return managedObjectModel;
}
/**
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.
*/
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (storeCoordinator != nil)
{
return storeCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"words_db.sqlite"];
NSError *error = nil;
storeCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![storeCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&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. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
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:
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
*/
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Oops!"
message:#"Something has gone terribly wrong! You need to reinstall the app in order for it to work properly."
delegate:nil
cancelButtonTitle:#"Close."
otherButtonTitles:nil, nil];
[alert show];
}
return storeCoordinator;
}
#pragma mark Application's Documents directory
/**
Returns the URL to the application's Documents directory.
*/
- (NSURL *)applicationDocumentsDirectory {
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
#end
You will also have to create an .xcdatamodeld file in order to create your Data Model objects. And replace the name here with appropriate
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"DataModel" withExtension:#"momd"];

How to remove a core data persistent store

I need to delete my persistent store (doing it object by object is not practical because I have over 100,000 objects). I've tried this:
- (IBAction)resetDatabase:(id)sender {
NSPersistentStore* store = [[__persistentStoreCoordinator persistentStores] lastObject];
NSError *error = nil;
NSURL *storeURL = store.URL;
// release context and model
[__managedObjectContext release];
[__managedObjectModel release];
__managedObjectModel = nil;
__managedObjectContext = nil;
[__persistentStoreCoordinator removePersistentStore:store error:nil];
[__persistentStoreCoordinator release];
__persistentStoreCoordinator = nil;
[[NSFileManager defaultManager] removeItemAtPath:storeURL.path error:&error];
if (error) {
NSLog(#"filemanager error %#", error);
}
// recreate the stack
__managedObjectContext = [self managedObjectContext];
}
But I get this error when I try to insert entities into the store afterwards:
This NSPersistentStoreCoordinator has no persistent stores. It cannot perform a save operation.
Update:
I tried releasing the MOC and MOM before removing the persistent store but I still get the same error.
Here is how I do a "reset data" function in several apps:
- (void)reset {
// Release CoreData chain
[_managedObjectContext release];
_managedObjectContext = nil;
[_managedObjectModel release];
_managedObjectModel = nil;
[_persistentStoreCoordinator release];
_persistentStoreCoordinator = nil;
// Delete the sqlite file
NSError *error = nil;
if ([fileManager fileExistsAtPath:_storeURL.path])
[fileManager removeItemAtURL:_storeURL error:&error];
// handle error...
}
Basically I just release the CoreData chain, then delete the persistentStore file. That's what you are trying to do, without using removePersistentStore, which I do not care since I will just rebuild the persistentStore coordinator later. Then at next core data call the chain is rebuilt transparently using singleton-lazy-style constructors like :
- (NSManagedObjectModel *) managedObjectModel {
if (!_managedObjectModel)
_managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];
return _managedObjectModel;
}
You can do it externally given that you only need to do this while developing your application. I have a terminal open in which I remove the store manually before re-running my app. All you need to know is where it is located. I log it to console everytime my app runs with the following code:
[[CoreDataSingleton sharedManager] managedObjectContext]; //be sure to create the store first!
//Find targeted mom file in the Resources directory
NSString *momPath = [[NSBundle mainBundle] pathForResource:#"Parking" ofType:#"mom"];
NSLog(#"momd path: %#",momPath);
Hope that helps!
You need to make sure that any managed object context attached to the persistent store have been released before you try to delete the store. Otherwise, the context will evoke that error.