rename persistentstore coordinator URL - iphone

i have a (proably) simple to fix issue with my coredata persistent store.
i created it with:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (persistentStoreCoordinator != nil)
{
return persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"dummyURL.sqlite"];
NSError *error = nil;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return persistentStoreCoordinator;
}
using the url dummyURL.sqlite
i did this on the first day working with the project, and have forgotten to rename it.. now all my current test devices (4) were in use for over 2 month, using the application, collecting a lot of data and storing it with a stupid url ^^
UPDATE i did some research on migration of persistent stores and wrote this function:
-(void)migrate{
NSPersistentStoreCoordinator *psc = [self.dataHandler.managedObjectContext persistentStoreCoordinator];
NSURL *oldURL = [psc URLForPersistentStore:[[psc persistentStores]objectAtIndex:0]];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSURL *newURL = [[appDelegate applicationDocumentsDirectory] URLByAppendingPathComponent:#"database.sqlite"];
NSError *error = nil;
NSPersistentStore *oldStore = [psc persistentStoreForURL:oldURL];
NSPersistentStore *newStore = [psc migratePersistentStore:sqliStoreOld
toURL:newURL
options:nil
withType:NSSQLiteStoreType
error:&error];
}
QUESTION 1 will this work or will i lose some data with that?
QUESTION 2 afterwards will i just have to change the appendString in my persistenstore function?

i managed to solve it myself using the migratePersistentStore function:
-(void)migrate{
NSPersistentStoreCoordinator *psc = [self.dataHandler.managedObjectContext persistentStoreCoordinator];
NSURL *oldURL = [psc URLForPersistentStore:[[psc persistentStores]objectAtIndex:0]];
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSURL *newURL = [[appDelegate applicationDocumentsDirectory] URLByAppendingPathComponent:#"database.sqlite"];
NSError *error = nil;
NSPersistentStore *oldStore = [psc persistentStoreForURL:oldURL];
NSPersistentStore *newStore = [psc migratePersistentStore:sqliStoreOld
toURL:newURL
options:nil
withType:NSSQLiteStoreType
error:&error];
}
afterwards i just changed the appendURL to database.sqli in my appDelegate.
works like a charm :)

I would recommend creating a second persistent store with the new URL and adding a button somewhere that copies all of the data you have into the new one.
Make sure you test to make sure all your data is in the new persistent store before you remove the old one from the app.

Related

Preloaded "Core data" database not showing the correct new data after updating the database

I have a predefined and preloaded database in my project named Database, i had define it as follow:
in the AppDelegate
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (__persistentStoreCoordinator != nil) {
return __persistentStoreCoordinator;
}
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"Database.sqlite"];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Database.sqlite"]; //este es el que sirve!!! CREE ESTE
// NSLog(#"store URL %#", storeURL);
// Put down default db if it doesn't already exist
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:writableDBPath]) {
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:#"Database" ofType:#"sqlite"];
if (defaultStorePath) {
[fileManager copyItemAtPath:defaultStorePath toPath:writableDBPath error:NULL];
}
}
NSError *error = nil;
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return __persistentStoreCoordinator;
}
And in any class i wanna call the data from the database i use:
-(NSArray *)sqlCall {
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext];
NSEntityDescription *entityDesc = [NSEntityDescription entityForName:#"MotherWeekly" inManagedObjectContext:context];
NSFetchRequest *request = [[ NSFetchRequest alloc] init];
[request setFetchLimit:1];
[request setEntity:entityDesc];
NSString *a =[NSString stringWithFormat:#"%#==%d",#"id",pageNumber];
NSPredicate *pred = [NSPredicate predicateWithFormat:a];
[request setPredicate:pred];
NSError *error;
NSArray *objects = [context executeFetchRequest:request
error:&error];
[request release];
return objects ;
}
The problem is: when i update a field in my preloaded database and run it on my simulator or iPhone the data appear to be the old one not the updated one.
PS: i had submitted my app to the AppStore before i noticed this problem, so im gonna reject my binary and upload a new version with the working/updated database, so please help me
Thanks in advance
Clearly, the store is not deleted when you have a new updated one. Therefore you see the old values.
If you want to delete the store if there is a new one, you could check for a NSUserDefault with a version or something that tells you if an update is necessary. If yes, delete the persistent store, copy the new one and set the user default to the new version.
However, all the user data would be lost then. There are two solutions to this:
1) You can have two persistent stores, one for "static" data and one for user data. However, this might be a bit too complex.
2) Alternatively, you could include information of the changed data and simply update the database (copy only if it does not exist, i.e. if it is a new installation). This would preserve the user data as well. In fact, if the data that needs to be updated is not much, it does not seem to make sense to copy the whole database again.
Indeed, if the database to be copied has less than, say, 10.000 records, copying a core data persistent store might be questionable. You could do a quick background insert at startup instead reading from any kind of file.

Crash When Saving On Device After Changing Datamodel

I've been hunting for a solution for the last four hours and I am posting in desperation. My app was working perfectly on the simulator, my iPhone, and my ipad until I added an attribute to one of my Data Models.
My iPhone application uses Core Data and iCloud. In the AppDelegate, I create the managedObjectModel by merging two models. Everything seems fine until I try to save the ManagedObjectContext. That's when it crashes with:
* Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'This
NSPersistentStoreCoordinator has no persistent stores. It cannot
perform a save operation.'
This does not happen on the simulator.
I have tried:
Project->Clean Build Folder
Project->Clean
Deleting the app from my
device
Deleting the iCloud data from my iCloud back up
reboot computer
changed the ".momd" to ".mom" and back again (read about it in another question)
Thanks for the help.
EDIT to add code:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (__persistentStoreCoordinator != nil) {
return __persistentStoreCoordinator;
}
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]];
NSPersistentStoreCoordinator *psc = __persistentStoreCoordinator;
// TODO: Set up iCloud in another thread:
//dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSString *dataFileName = [NSString stringWithFormat:#"%#.sqlite", APP_TITLE_NO_SPACES];
NSString *iCloudDataDirectoryName = #"Data.nosync";
NSString *iCloudLogsDirectoryName = #"Logs";
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *localStore = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:dataFileName];
NSURL *iCloud = [fileManager URLForUbiquityContainerIdentifier:nil];
if (iCloud) {
NSURL *iCloudLogsPath = [NSURL fileURLWithPath:[[iCloud path] stringByAppendingPathComponent:iCloudLogsDirectoryName]];
if([fileManager fileExistsAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]] == NO) {
NSError *fileSystemError;
[fileManager createDirectoryAtPath:[[iCloud path] stringByAppendingPathComponent:iCloudDataDirectoryName]
withIntermediateDirectories:YES
attributes:nil
error:&fileSystemError];
if(fileSystemError != nil) {
NSLog(#"Error creating database directory %#", fileSystemError);
}
}
NSString *iCloudData = [[[iCloud path]
stringByAppendingPathComponent:iCloudDataDirectoryName]
stringByAppendingPathComponent:dataFileName];
NSLog(#"iCloudData = %#", iCloudData);
NSDictionary* options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
CLOUD_CONTAINER_IDENTIFIER, NSPersistentStoreUbiquitousContentNameKey,
iCloudLogsPath, NSPersistentStoreUbiquitousContentURLKey, nil];
[psc lock];
[psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:[NSURL fileURLWithPath:iCloudData]
options:options
error:nil];
[psc unlock];
} else {
NSLog(#"iCloud is NOT working - using a local store");
NSMutableDictionary *options = [NSMutableDictionary dictionary];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
[psc lock];
[psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:localStore
options:options
error:nil];
[psc unlock];
}
__persistentStoreCoordinator = psc;
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_ICLOUD_SOMETHING_CHANGED object:nil];
return __persistentStoreCoordinator;
}
Usually, it should okay after you deleted the program data. However, error indicates, that you do not have an inconsistency but simply no store at all. Assumption: you do not re-initiate it in case of a fault. Maybe, the following code can be useful:
- (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]) {
// Error, erase data
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil];
NSLog(#"store cleaned");
__persistentStoreCoordinator = nil;
return [self persistentStoreCoordinator];
}
return __persistentStoreCoordinator;
}

Core data storage is repeated

I am trying to use Core Data in my application and I have been succesful in storing data into the entity.The data storage is done in the applicationDidFinishLaunchingWithOptions() method.But when I run the app again,it again gets saved.So how do I check if the data is already present or not??
Here is the code(Saving):
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObject *failedBankInfo = [NSEntityDescription
insertNewObjectForEntityForName:#"FailedBankInfo"
inManagedObjectContext:context];
[failedBankInfo setValue:#"Test Bank" forKey:#"name"];
[failedBankInfo setValue:#"Testville" forKey:#"city"];
[failedBankInfo setValue:#"Testland" forKey:#"state"];
NSError *error;
if (![context save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}
(Retrieving):-
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
entityForName:#"FailedBankInfo" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
for (NSManagedObject *info in fetchedObjects) {
NSLog(#"Name: %#", [info valueForKey:#"name"]);
}
`
Another thing I want to know that if I have thousands of records to store,then is there any other way to do it or can it be done through coding only???
Thanks
from what i understand you want to add all the data once only one time?
if so, move the inserting to the persistentStoreCoordinator method, and check if this is the first time the app lunches, by checking :
if (![[NSFileManager defaultManager] fileExistsAtPath:[storeURL path] isDirectory:NULL]) {
firstRun = YES;
}
if it does then load the data. if not do nothing. this is how it look's at the end :
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator_ != nil) {
return persistentStoreCoordinator_;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"your_app.sqlite"];
BOOL firstRun = NO;
if (![[NSFileManager defaultManager] fileExistsAtPath:[storeURL path] isDirectory:NULL]) {
firstRun = YES;
}
NSError *error = nil;
persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
if (firstRun) {
NSManagedObject *failedBankInfo = [NSEntityDescription
insertNewObjectForEntityForName:#"FailedBankInfo"
inManagedObjectContext:context];
[failedBankInfo setValue:#"Test Bank" forKey:#"name"];
[failedBankInfo setValue:#"Testville" forKey:#"city"];
[failedBankInfo setValue:#"Testland" forKey:#"state"];
NSError *error;
[moc save:&error];
}
return persistentStoreCoordinator_;
}
a.the way i do that is to create a plist with all the data.
b.import the plist as array of dictionaries (each dictionary is an entity".
c. set a function that iterates throw the array and adds the entities to the context.
something like that:
NSString *thePath = [[NSBundle mainBundle] pathForResource:#"recordsList" ofType:#"plist"];
NSArray *recordsArray = [[NSArray alloc] initWithContentsOfFile:thePath];
for (int i=0;i<[recordsArray count];i++)
{
//add the objects to the context
}
}
I have tried to simplify the answer, but you should know there are alot of thing you can do to better the process.
good luck

coredata importing sqlite but not saving new data Cocoa error 256

EDIT, // REASON FOR NOT SAVING>
so I put some nslog in my saveData (plese check in below code), after saving edited, and saved new data,
for the edited, is fine
but for the new,, I get>
Error The operation couldn’t be completed. (Cocoa error 256.)
** Second Edit>
if I edit and save the first time, it saves fine the edited data, but shows error 256 for new data,
but if I try to save the edited data after having the 256 error (by trying to save new data), then the edited data shows error 256 when saving and doesnt get saved!!!!
Im importing some sqlitedb (the same that coredata generates but with some prepopulated tables)
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator_ != nil) {
return persistentStoreCoordinator_;
}
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:#"ChildCare_v02.sqlite"];
NSString *storePath = [[NSBundle mainBundle] pathForResource:#"ChildCare_v02" ofType:#"sqlite"];
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"ChildCare_v02.sqlite"]; //este es el que sirve!!! CREE ESTE
NSLog(#"store URL %#", storeURL);
// Put down default db if it doesn't already exist
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:writableDBPath]) {
NSLog(#"proceda aqui");
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:#"ChildCare_v02" ofType:#"sqlite"];
NSLog(#"no existe todavia");
NSLog(#"defalultStorePath %#", defaultStorePath);
if (defaultStorePath) {
[fileManager copyItemAtPath:defaultStorePath toPath:writableDBPath error:NULL];
NSLog(#"storePath= %#", storePath);
}
}
NSError *error = nil;
persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return persistentStoreCoordinator_;
}
it creates the new db fine, and populates it with the existing data, when I edit the data (prepopulated), in the app, it saves this data (checked in simulator document with sqlite manager, and going out and in again), but if I create a new entry, it shows in the table showing the data, but when I leave the app, and come back then this newly created entry is not there (and of course not in the sqlite new db)...
this is the code I use for saving edited data or newly created data,
-(IBAction)saveData
{
if(editFlag==1)
{
NSManagedObjectContext *context = [(ChildCare_v01AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Employee" inManagedObjectContext:context];
[request setEntity:entity];
editEmp.namemployee = tfName.text;
editEmp.surname = tfSurname.text;
editEmp.email = tfEmail.text;
//editEmp.phone = tfPhone.text;
editEmp.mobile = tfMobile.text;
editEmp.category=tfCategory.text;
NSLog(#"salvado editado"); //saving FINE!!!!
NSError *error;
if (![context save:&error])
{ NSLog(#"Error %#",[error localizedDescription]); }
//[context release];
[self.navigationController popViewControllerAnimated:TRUE];
}
else{
NSManagedObjectContext *context = [(ChildCare_v01AppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
Employee *employee = (Employee*)[NSEntityDescription
insertNewObjectForEntityForName:#"Employee"
inManagedObjectContext:context];
employee.namemployee = tfName.text;
employee.surname = tfSurname.text;
employee.email = tfEmail.text;
//employee.phone=tfPhone.text;
employee.mobile = tfMobile.text;
employee.category=tfCategory.text;
NSLog(#"salvado nuevo"); ///HERE THE ERROR!! COCOA ERROR 256!!!!
NSError *error;
if (![context save:&error]) {
NSLog(#"Error %#",[error localizedDescription]);
// handle error
} else {
NSLog(#"Done");
}
[self.navigationController popViewControllerAnimated:TRUE];
}
}
so its it possible to save the newly created data?? why is not working? why only saves edits? and no new data?, please help me to achieve this, thanks a lot!
A couple things to try:
1. Make sure the managedObjectContext has a non-null value before you save to it.
2. Is your db initialization code re-installing the original db (thereby losing your changes)?
Good luck.

Will Core Data create the persistent store file for me?

Please tell me: If I use Core Data in my iPhone app, I have basically two files. The mydatamodel.xcdatamodel file, and then I need an .sqlite file. Apple provides this code snippet:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
NSString *appDirPath = [self applicationDocumentsDirectory];
NSString *storeFileName = #"mystore.sqlite";
NSURL *storeUrl = [NSURL fileURLWithPath:[appDirPath stringByAppendingPathComponent:storeFileName]];
NSError *error = nil;
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error]) {
NSLog(#"Error: %#, %#", error, [error userInfo]);
abort();
}
return persistentStoreCoordinator;
}
Will this create the file if it's not available already?
[persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error]
My app doesn't need initial data, because it will download it when the user launches the app.
Yes, Core Data will create the SQLite db just after the first launch of your application in your app delegate.
Yes. The boiler-plate Core Data stack code provided by Apple's templates will create the database file if it doesn't already exist.
Yes, that method adds a new persistent store of a specified type at a given location, and returns the new store. Here is the documentation.