Core Data Model path vs Store path - objective-c

Previously, I have an app that uses core data. I use same store url to init NSManagedObjectModel and create NSPersistentStoreCoordinator. However, in the new app, I tried to use the same way, the model can not be created. So I have to use a model url (I found it in this forum) to be able to create NSManagedObjectModel. What is the issue?
Here is from OLD app:
- (NSString *)storeName
{
return #"ABC.storedata";
}
- (NSURL *)storeUrl
{
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:self.storeName];
return storeURL;
}
- (NSManagedObjectModel *)managedObjectModel {
if (_managedObjectModel == nil) {
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:[self storeUrl]];
}
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[self storeUrl] options:nil error:&error]) {
abort();
}
return _persistentStoreCoordinator;
}
Here is from NEW app:
- (NSString *)storeName
{
return #"DEF.sqlite";
}
- (NSURL *)storeUrl
{
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:self.storeName];
return storeURL;
}
- (NSURL *)modelUrl
{
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"DEF" withExtension:#"momd"];
return modelURL;
}
- (NSManagedObjectModel *)managedObjectModel {
if (_managedObjectModel == nil) {
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:[self modelUrl]];
}
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[self storeUrl] options:nil error:&error]) {
abort();
}
return _persistentStoreCoordinator;
}

You can never use the same URL for both model and persistent store because they are two very different things.
Model URL must point to the actual model resource included in your Xcode project which is a .momd file package. Persistent store is in your case a database, a .sqlite file in documents directory.
I cannot imagine how it could have worked in the past. One possibility is that since your ABC.storedata did not have a trailing .sqlite, Core Data must have added a .sqlite to it behind the scenes and DEF.storedata could have matched your model name somehow?
This is the proper way to initialize a model where you replace "Model" with the name you have in the Xcode project for model resource:
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"Model" withExtension:#"momd"];
model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
As for persistent store, there are no restrictions. In most cases it should be in application documents directory though.

Related

how we make persistentStoreCoordinator synchronize in objective c

I am new in objective c and I want to know how we make persistentStoreCoordinator #synchronize to make methods thread safe. It's crash, i can clearly see crash reason on sigabort
This NSPersistentStoreCoordinator has no persistent stores (unknown). It cannot perform a save operation.
Please provide me any link or sample where we can check persistentStoreCoordinator is synchronize.
Any help is appreciated. Thanks in advance.
-(NSManagedObjectContext *)managedObjectContext
{
#try{
if (__managedObjectContext != nil) {
return __managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
__managedObjectContext = [[NSManagedObjectContext alloc] init];
[__managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return __managedObjectContext;
}
#catch(NSException *exception){
NSLog(#"Exception managedObjectContext : %#", exception);
}
}
-(NSManagedObjectModel *)managedObjectModel
{
#try{
if (__managedObjectModel != nil) {
return __managedObjectModel;
}
NSString *modelPath = [[NSBundle mainBundle] pathForResource:DBNAME ofType:#"momd"];
if([[TrackerUtility TrackerUtilityManager] getDebugMode]){
NSLog(#"modelPath %#",modelPath);
}
NSURL *modelURL = [NSURL fileURLWithPath:modelPath];
__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return __managedObjectModel;
}
#catch(NSException *exception){
NSLog(#"Exception managedObjectModel : %#",exception);
}
}
-(NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
#try{
if (__persistentStoreCoordinator != nil) {
return __persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:[NSString stringWithFormat:#"%#.sqlite", DBNAME]];
NSError *error = nil;
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSDictionary *options = #{
NSMigratePersistentStoresAutomaticallyOption : #YES,
NSInferMappingModelAutomaticallyOption : #YES
};
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
if([[TrackerUtility TrackerUtilityManager] getDebugMode]){
NSLog(#"persistentStoreCoordinator error %#, %#", error, [error userInfo]);
}
abort();
}
return __persistentStoreCoordinator;
}
#catch(NSException *exception){
NSLog(#"Exception persistentStoreCoordinator : %#",exception);
}
}
(NSURL *)applicationDocumentsDirectory
{
#try{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
#catch(NSException *exception){
NSLog(#"Exception applicationDocumentsDirectory : %#",exception);
}
}

NSManagedObjectContext is nil in the UITableViewController class using CoreData

i need to display a few elements in a UITableViewController from CoreData, but the NSManagedObjectContext instance, called *managedObjectContext, is nil when the app launching.
This is my UITableViewController.h
#interface TableViewController : UITableViewController
#property(nonatomic,strong) NSArray *listaElementi;
#property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; //si occupa di gestire come sono strutturate le entity
#end
This is my UITableViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Stato" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];
NSError *error;
self.listaElementi = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
self.title = #"Stati";
Finally this is my AppDelegate.m
#synthesize managedObjectContext = _managedObjectContext;
#synthesize managedObjectModel = _managedObjectModel;
#synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
- (NSManagedObjectModel *)managedObjectModel {
// The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"Model" withExtension:#"momd"]; //SETTARE BENE IL MODELLO
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
// The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it.
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
// Create the coordinator and store
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Database.sqlite"];
NSError *error = nil;
NSString *failureReason = #"There was an error creating or loading the application's saved data.";
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// Report any error we got.
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[NSLocalizedDescriptionKey] = #"Failed to initialize the application's saved data";
dict[NSLocalizedFailureReasonErrorKey] = failureReason;
dict[NSUnderlyingErrorKey] = error;
error = [NSError errorWithDomain:#"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
// Replace this 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();
}
return _persistentStoreCoordinator;
}
- (NSManagedObjectContext *)managedObjectContext {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
return nil;
}
_managedObjectContext = [[NSManagedObjectContext alloc] init];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
}
Could you help me? When I created the project I don't checked the adding core data box , but I implemented all manually and I just created the model and I just Inserted a few element into the Database, is a possible cause of the problem?
Try this in viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
AppDelegate *delgate = (AppDelegate *)[[UIApplication
sharedApplication]delegate];
self.managedObjectContext = delegate.managedObjectContext;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"Stato" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSError *error;
self.listaElementi = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];
}

Core Data sqlite file embedded in my app?

I'm trying to make a little dictionary on my app by using Core Data.When you use a Master-Detail application, xxx.sqlite file gets created in the user's Documents folder. Now before I start the application for the first time, I changed the code as below because I wanted the xxx.sqlite file in the app:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
//NSURL *storeURL = [[self applicationDocumentsDirectory]
URLByAppendingPathComponent:#"CoreDataFileTest.sqlite"];
NSString* path= [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"CoreDataTest.sqlite"];
NSURL* storeURL = [[NSURL alloc] initFileURLWithPath:path];
I thought the last two line would make a xxx.sqlite file in my app project folder.
Actually, it didn't. But the app works fine. This means that the xxx.sqlite file is embedded in the app itself? Thank you for your time.
If, as I understand your question, you would like to include a default database with your app (i.e. the .sqlite file will be included as an asset of your project, then you need to copy it from the app bundle into your documents directory at startup).
Then call this function from your didFinishLaunchingWithOptions method in your app delegate.
- (void) copyDefaultDB
{
// If we are running the app for the first time, then copy our default database across from our app directory
// into our user directory
NSString *filePath;
// Get the path to the documents directory and append the databaseName
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex: 0];
NSFileManager *fileManager = [NSFileManager defaultManager];
filePath = [documentsDir stringByAppendingPathComponent: #"CoreDataFileTest.sqlite"];
// If the database already exists then return without doing anything
if (![fileManager fileExistsAtPath: filePath])
{
// Now copy the new shiny one in
NSString *filePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent: #"CoreDataFileTest.sqlite"];
// Copy the database from the package to the users filesystem
[fileManager copyItemAtPath: filePathFromApp
toPath: filePath
error: nil];
}
}
Try with this code. Write this inside AppDelegate.m
- (NSManagedObjectContext *) managedObjectContext {
if (managedObjectContext != nil) {
return managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator: coordinator];
}
return managedObjectContext;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory]
stringByAppendingPathComponent: #"ProjectManagement.sqlite"]];
NSError *error = nil;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc]
initWithManagedObjectModel:[self managedObjectModel]];
if(![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeUrl
options:nil error:&error]){
/*Error for store creation should be handled in here*/
}
return persistentStoreCoordinator;
}
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel != nil) {
return managedObjectModel;
}
managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
return managedObjectModel;
}
- (NSString*)applicationDocumentsDirectory{
return [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES) objectAtIndex:0];
}

How create separate sqlite file with self model

I have read this post Core Data with mutiple sqlite files and some else.
However not find any intelligible information about creation separated sqlite files (for example to store some data for different users). That's what I'm doing:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (__persistentStoreCoordinator != nil)
{
return __persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:[NSString stringWithFormat:#"%#.sqlite", _userID]];
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
NSError *error = nil;
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return __persistentStoreCoordinator;
}
- (NSManagedObjectModel *)managedObjectModel {
if (__managedObjectModel != nil) {
return __managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:#"DataBase" withExtension:#"momd"];
__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return __managedObjectModel;
}
- (NSManagedObjectContext *)managedObjectContext
{
if (__managedObjectContext != nil)
{
return __managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
{
__managedObjectContext = [[NSManagedObjectContext alloc] init];
[__managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return __managedObjectContext;
}
If you change the user also changes NSPersistentStoreCoordinator and NSManagedObjectContext but NSManagedObjectModel - not (there NSFetchRequest). So how to separate core data (with self data and the "fetch requests") for different user without creating additionally entity(like user)?
Perhaps you could use multiple contexts with their own stores, but based on the same data model. In this way you could use the same entities for the different stores.

Error after adding a new core data model version

I added a new model version, and I set the core data model to use that new version, but I get this error when the application tries to start.
"The managed object model version used to open the persistent store is incompatible with the one that was used to create the persistent store."
I'm guessing the problem is that the current persistent store is the old version of the model. Is there a way to just delete it so it makes a new one? I don't care about saving any of that data.
You have to migrate between versions. According to Apple's docs, if the changes are simple, you can do lightweight migration.
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/vmLightweight.html#//apple_ref/doc/uid/TP40008426-SW1
Adding these options to the NSPersistentStoreCoordinator seemed to work.
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
NSURL *url = [applicationFilesDirectory URLByAppendingPathComponent:#"YOURAPP.storedata"];
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSXMLStoreType configuration:nil URL:url options:options error:&error]) {
[[NSApplication sharedApplication] presentError:error];
[persistentStoreCoordinator release], persistentStoreCoordinator = nil;
return nil;
}
return persistentStoreCoordinator;
In answer to your question, "Is there a way to delete it so it just makes a new one ?"
Yes.
Just change the persistentStoreCoordinator getter in your App Delegate as follows:
- (NSPersistentStoreCoordinator *) persistentStoreCoordinator {
if (persistentStoreCoordinator) return persistentStoreCoordinator;
NSManagedObjectModel *mom = [self managedObjectModel];
if (!mom) {
NSAssert(NO, #"Managed object model is nil");
NSLog(#"%#:%s No model to generate a store from", [self class], (char *)_cmd);
return nil;
}
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *applicationSupportDirectory = [self applicationSupportDirectory];
NSError *error = nil;
if ( ![fileManager fileExistsAtPath:applicationSupportDirectory isDirectory:NULL] ) {
if (![fileManager createDirectoryAtPath:applicationSupportDirectory withIntermediateDirectories:NO attributes:nil error:&error]) {
NSAssert(NO, ([NSString stringWithFormat:#"Failed to create App Support directory %# : %#", applicationSupportDirectory,error]));
NSLog(#"Error creating application support directory at %# : %#",applicationSupportDirectory,error);
return nil;
}
}
NSURL *url = [NSURL fileURLWithPath: [applicationSupportDirectory stringByAppendingPathComponent: #"storedata"]];
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: mom];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSXMLStoreType
configuration:nil
URL:url
options:nil
error:&error]){
// EDIT: if error opening persistent store, remove it and create a new one
if([[error domain] isEqualToString:#"NSCocoaErrorDomain"] && [error code] == 134100) {
NSLog(#"Core Data model was updated. Deleting old persistent store.");
[[NSFileManager defaultManager] removeItemAtURL:url error:nil];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSXMLStoreType
configuration:nil
URL:url
options:nil
error:&error]){
[[NSApplication sharedApplication] presentError:error];
[persistentStoreCoordinator release], persistentStoreCoordinator = nil;
return nil;
}
} else {
[[NSApplication sharedApplication] presentError:error];
[persistentStoreCoordinator release], persistentStoreCoordinator = nil;
return nil;
}
//
}
return persistentStoreCoordinator;
}
Figure out where your app stored the document and put it in the trash.
But as a extended comment you may wish to examine the possibilities around both explicit and implicit migration in NSPersistentStoreCoordinator and the options in.
- (NSPersistentStore *)addPersistentStoreWithType:(NSString *)storeType configuration:(NSString *)configuration URL:(NSURL *)storeURL options:(NSDictionary *)options error:(NSError **)error
Depending how different the versions are you can get it to happen automagically by passing NSMigratePersistentStoresAutomaticallyOption & NSInferMappingModelAutomaticallyOption
theres also
- (NSPersistentStore *)migratePersistentStore:(NSPersistentStore *)store toURL:(NSURL *)URL options:(NSDictionary *)options withType:(NSString *)storeType error:(NSError **)error