Core Data Migration Fail [duplicate] - ios

This question already has answers here:
Fix Core Data Fail
(3 answers)
Closed 9 years ago.
My app was recently crashing on the app store because I did not migrate the data. So I was following this tutorial on Core Data Migration but it does not seem to be working:
1.I created a new model version for Core Data and set it to the current version...
2.I added the following code:
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"Planner.sqlite"];
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]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
However when I run update the app on my iPhone it still crashes!
The changes I made was I added an entity.
Here is the crash log:
Unresolved error Error Domain=NSCocoaErrorDomain Code=134130 "The operation couldn’t be completed. (Cocoa error 134130.)" UserInfo=0x14fb4530 {URL=file:///var/mobile/Applications/E8C39F0E-027E-4D5B-8D7B-74D592290D46/Documents/Planner.sqlite, metadata={
NSPersistenceFrameworkVersion = 479;
NSStoreModelVersionHashes = {
Audio = <f195c962 11c85401 0457370e e1b037e1 24c4e393 dc38ca34 cda3bb57 a3e26f2c>;
Classes = <3b64e147 eb41441b 73bf051f ce094443 2017845b 2faba1c7 47848618 9fd9713b>;
Homework = <4295bdbf 75862060 c7f1a501 3b0934cd 9811e838 bc40c5d5 05f8d383 f315d1f8>;
Notes = <b7be1214 70a89b62 924df103 397a801a 96080505 be87b0e2 408ebf24 fdddb1a7>;
Picture = <451cd1a2 9daac38d 69165176 0cacb6c8 94d1e93d eca34239 61a15f35 573f7e40>;
Tests = <c10b5b25 228ebceb 6099b9af c830d203 bfca8e2b c9f46ee8 c0cd648e 9ad3e742>;
Video = <b95e2033 b45b5aaf 298fef31 e6e25685 2b842e4e f2b3d9d1 82359c5f db9c78eb>;
};
NSStoreModelVersionHashesVersion = 3;
NSStoreModelVersionIdentifiers = (
""
);
NSStoreType = SQLite;
NSStoreUUID = "4327E676-759B-4733-A7ED-12309BD482EE";
"_NSAutoVacuumLevel" = 2;
}, reason=Can't find model for source store}, {
URL = "file:///var/mobile/Applications/E8C39F0E-027E-4D5B-8D7B-74D592290D46/Documents/Planner.sqlite";
metadata = {
NSPersistenceFrameworkVersion = 479;
NSStoreModelVersionHashes = {
Audio = <f195c962 11c85401 0457370e e1b037e1 24c4e393 dc38ca34 cda3bb57 a3e26f2c>;
Classes = <3b64e147 eb41441b 73bf051f ce094443 2017845b 2faba1c7 47848618 9fd9713b>;
Homework = <4295bdbf 75862060 c7f1a501 3b0934cd 9811e838 bc40c5d5 05f8d383 f315d1f8>;
Notes = <b7be1214 70a89b62 924df103 397a801a 96080505 be87b0e2 408ebf24 fdddb1a7>;
Picture = <451cd1a2 9daac38d 69165176 0cacb6c8 94d1e93d eca34239 61a15f35 573f7e40>;
Tests = <c10b5b25 228ebceb 6099b9af c830d203 bfca8e2b c9f46ee8 c0cd648e 9ad3e742>;
Video = <b95e2033 b45b5aaf 298fef31 e6e25685 2b842e4e f2b3d9d1 82359c5f db9c78eb>;
};
NSStoreModelVersionHashesVersion = 3;
NSStoreModelVersionIdentifiers = (
""
);
NSStoreType = SQLite;
NSStoreUUID = "4327E676-759B-4733-A7ED-12309BD482EE";
"_NSAutoVacuumLevel" = 2;
};
reason = "Can't find model for source store";
}
I already set the current model version.
Any help will be appreciated.
Thank you in advance,
Abdullah Shafique
According to #Scott I have to undo all the changes to my source and only change the destination
Can someone please explain the?

Try using this code to check the model versions and output the metadata
/*! The method checks the Core Data file version is compatible with the App's model version
and then pushes the main menu view onto the navigation stack. If not compatible it displays a
message to the user.
#param file The file URL for the Core Data Store. With UIManagedDocument you have to get the
actual store file URL, you can't just use the UIManagedDocument file URL.
*/
-(voidcheckCoreDataFileVersion:(NSURL*)file
{
if ([self checkVersion:file]) {
// file version is compatible so continue (add code to push the menu view)
} else {
// file version is NOT compatible
_fileOpenErrorAlert = [[UIAlertView alloc] initWithTitle:#"Unable to open Document" message:#"Please check that you have the correct application version installed" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[_fileOpenErrorAlert show];
}
return;
}
/*! Checks the Core Data files models version against the apps model version to see if they
are compatible. This will return YES if a lightweight migration can be performed and NO if NOT.
#param fileURL The file URL for the Core Data Store. With UIManagedDocument you have to get the
actual store file URL, you can't just use the UIManagedDocument file URL.
#return Returns YES if they are compatible and NO if not.
*/
- (bool)checkVersion:(NSURL*)fileURL {
NSManagedObjectModel *model = [self managedObjectModel];
NSLog(#" app model entity version hashes are %#", [model entityVersionHashesByName]);
NSError *error;
NSDictionary *metaData = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:fileURL error:&error];
if (!metaData) {
NSLog(#“ problem getting metaData");
NSLog(#“ - error is %#, %#", error, error.userInfo);
return NO;
}
bool result = [model isConfiguration:nil compatibleWithStoreMetadata:metaData];
if (!result) {
NSLog(#“ file is not compatible!");
NSLog(#“ metadata is %#", metaData);
}
return result;
}

The error says:
"Can't find model for source store";
It looks like you also modified previous model and hashes were regenerated. And they do not match, and because of that model for source store can not be found.

When you add a new Core Data model version XCode creates another model and you are prompted to provide a Model name for the new version. So now you should have two models in the XCode project. Once you have created the new version you then need to select it and set it to be the current version to be used by the application. You keep the old version of the model in the project.
In order for Core Data to open your existing files it needs the old version of the model (model for source store). It will then perform a migration by moving the data to the new schema (or model).
So the error above indicates that you have inadvertently made changes to the original version of the model (perhaps in addition to changes to the new version). However Core Data is unable to open the file without the correct model version so you need to restore a copy of the original core data model. If all you did was add a new entity to the new model then check whether this new entity has inadvertently been added to the old model and if so simply delete it from the old version of the model.

Related

Core data crashes the app [duplicate]

I created a Core Data model in xcode 3.2 and after upgrading in Xcode 4.2, I then added a new entity of the NSManagedObject subclass (refer to the new entity).
First thing, it looks weird because it's not in the same group as the old one. Here is the picture on my xcode 4.2 (AlkitabDB is the one i created in xcode 3.2, EndeDB is the new one from current xcode version(4.2):
Second thing, I let it as it is, then I accessed the second entity (the new one) the same way as the first entity (the old one), and the error as titled appears.
Here is the error:
2012-01-16 21:13:38.496 iHuria[55953:207] Unresolved error Error Domain=NSCocoaErrorDomain Code=134100 "The operation couldn’t be completed. (Cocoa error 134100.)" UserInfo=0x8829cd0 {metadata=<CFBasicHash 0x882a370 [0x1839b38]>{type = immutable dict, count = 7,
entries =>
2 : <CFString 0x8829b90 [0x1839b38]>{contents = "NSStoreModelVersionIdentifiers"} = <CFArray 0x8829ff0 [0x1839b38]>{type = immutable, count = 0, values = ()}
4 : <CFString 0x8829bc0 [0x1839b38]>{contents = "NSPersistenceFrameworkVersion"} = <CFNumber 0x8829770 [0x1839b38]>{value = +320, type = kCFNumberSInt64Type}
6 : <CFString 0x8829bf0 [0x1839b38]>{contents = "NSStoreModelVersionHashes"} = <CFBasicHash 0x882a080 [0x1839b38]>{type = immutable dict, count = 1,
entries =>
0 : <CFString 0x882a010 [0x1839b38]>{contents = "AlkitabDB"} = <CFData 0x882a030 [0x1839b38]>{length = 32, capacity = 32, bytes = 0xd02ac5f8be6ab0b39add450aca202ac0 ... 3d45d462998d2ccd}
}
7 : <CFString 0x10e3aa8 [0x1839b38]>{contents = "NSStoreUUID"} = <CFString 0x8829e60 [0x1839b38]>{contents = "4F2EE7FF-463B-4055-BBED-8E603CDBDF59"}
8 : <CFString 0x10e3948 [0x1839b38]>{contents = "NSStoreType"} = <CFString 0x10e3958 [0x1839b38]>{contents = "SQLite"}
9 : <CFString 0x8829c40 [0x1839b38]>{contents = "NSStoreModelVersionHashesVersion"} = <CFNumber 0x6b1c7c0 [0x1839b38]>{value = +3, type = kCFNumberSInt32Type}
10 : <CFString 0x8829c70 [0x1839b38]>{contents = "_NSAutoVacuumLevel"} = <CFString 0x882a0c0 [0x1839b38]>{contents = "2"}
}
, reason=The model used to open the store is incompatible with the one used to create the store}, {
metadata = {
NSPersistenceFrameworkVersion = 320;
NSStoreModelVersionHashes = {
AlkitabDB = <d02ac5f8 be6ab0b3 9add450a ca202ac0 ebd1e860 cbb578c2 3d45d462 998d2ccd>;
};
NSStoreModelVersionHashesVersion = 3;
NSStoreModelVersionIdentifiers = (
);
NSStoreType = SQLite;
NSStoreUUID = "4F2EE7FF-463B-4055-BBED-8E603CDBDF59";
"_NSAutoVacuumLevel" = 2;
};
reason = "The model used to open the store is incompatible with the one used to create the store";
}
I looked for the solution before and discovered that I should remove the appliation from simulator and rerun the app, and it didn't work.
Does anyone know a solution for this issue?
Please help.
Deleting the app is sometimes not the case! Suggest, your app has already been published! You can't just add new entity to the data base and go ahead - you need to perform migration!
For those who doesn't want to dig into documentation and is searching for a quick fix:
Open your .xcdatamodeld file
click on Editor
select Add model version...
Add a new version of your model (the new group of datamodels added)
select the main file, open file inspector (right-hand panel)
and under Versioned core data model select your new version of data model for current data model
THAT'S NOT ALL ) You should perform so called "light migration".
Go to your AppDelegate and find where the persistentStoreCoordinator is being created
Find this line if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
Replace nil options with #{NSMigratePersistentStoresAutomaticallyOption:#YES, NSInferMappingModelAutomaticallyOption:#YES} (actually provided in the commented code in that method)
Here you go, have fun!
P.S. This only applies for lightweight migration. For your migration to qualify as a lightweight migration, your changes must be confined
to this narrow band:
Add or remove a property (attribute or relationship).
Make a nonoptional property optional.
Make an optional attribute nonoptional, as long as you provide a default value.
Add or remove an entity.
Rename a property.
Rename an entity.
For Swift 4
coordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true])
Remove the app from the simulator and perform a clean on your project. That should clear those issues up. Make sure that you are not running in the debugger when you delete the app or else it won't actually delete it properly.
If you want to be sure its gone, check this directory Users/INSERT_YOUR_USER_HERE/Library/Application Support/iPhone Simulator/ for your app's folder, under the version you're running.
Note: This is for development only. For production, you need to implement some sort of migration. Google "Core Data Migration", with lightweight migration being the simplest.
Just add Options attribute while creating persistentStoreCoordinator in AppDelegate.m file for the core data method as below
OBJECTIVE-C
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil)
{
return _persistentStoreCoordinator;
}
NSLog(#"persistentStoreCoordinator___");
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:#"MyApp.sqlite"];
NSMutableDictionary *options = [[NSMutableDictionary alloc] init];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSMigratePersistentStoresAutomaticallyOption];
[options setObject:[NSNumber numberWithBool:YES] forKey:NSInferMappingModelAutomaticallyOption];
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])
{
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
NSLog(#"persistentStoreCoordinator___2");
return _persistentStoreCoordinator;
}
SWIFT
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator = {
// The persistent store coordinator for the application. This implementation creates and returns a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail.
// Create the coordinator and store
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
// MAIN LINE OF CODE TO ADD
let mOptions = [NSMigratePersistentStoresAutomaticallyOption: true,
NSInferMappingModelAutomaticallyOption: true]
do {
try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: mOptions)
} catch {
// Report any error we got.
var dict = [String: AnyObject]()
dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
dict[NSLocalizedFailureReasonErrorKey] = failureReason
dict[NSUnderlyingErrorKey] = error as NSError
let wrappedError = NSError(domain: "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 \(wrappedError), \(wrappedError.userInfo)")
abort()
}
return coordinator
}
It had solved my problem..
Answer : Remove the app from the Simulator , Perform a Clean and Re-Build your Project.
Note : Whenever you perform changes to the Core Data definition, Delete the app installed on the Physical Device or Simulator, Clean the Project and Re-Build again.
Yes. Once you delete app on physical device and rebuild it works.
For swift, in AppDelegate.swift find the line
try coordinator!.addPersistentStoreWithType(NSXMLStoreType, configuration: nil, URL: url, options: nil )
and replace it with
try coordinator!.addPersistentStoreWithType(NSXMLStoreType, configuration: nil, URL: url, options: [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true])
I just spent several days fighting this error, as well as mergedModelFromBundles crashes, and getting the "Can't merge models with two different entities named *" error.
It turns out the root problem was that Xcode doesn't remove old resources from devices and I had old versions of my data model (.mom files) that were causing conflicts. This is why deleting the app fixed the problem on one of my devices.
After finding this blog post via another SO answer I made my app more tolerant of old models by changing this line which looks for ALL .mom files:
NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
to this, which only looks in the Filters directory:
NSString *path = [[NSBundle mainBundle] pathForResource:#"Filters" ofType:#"momd"];
NSURL *momURL = [NSURL fileURLWithPath:path];
NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:momURL];
I used recursivePathsForResourcesOfType from this so question: to help figure this out by logging all of the .mom files in the app:
NSArray *momPaths = [self recursivePathsForResourcesOfType:#"mom" inDirectory:[[NSBundle mainBundle] resourcePath]];
NSLog(#"All .mom files:%#",momPaths);
I also used iExplorer to look at the extraneous .mom files (I didn't try deleting them yet).
The method below was also helpful. It showed that an entity was in the merged model returned by [psc managedObjectModel] that didn't exist any more in any of my models or in the store itself. This was what let me to believe an old model was being cached on the device itself that clean building didn't remove. The method logs each entity that is the same, been changed, or added to, or removed from the model. (written with this SO answer as a starting point):
- (BOOL)comparePersistentStore:(NSPersistentStoreCoordinator *)psc withStoreURL: (NSURL *)storeURL {
NSError *error = nil;
// Get the entities & keys from the persistent store coordinator
NSManagedObjectModel *pscModel = [psc managedObjectModel];
NSDictionary *pscEntities = [pscModel entitiesByName];
NSSet *pscKeys = [NSSet setWithArray:[pscEntities allKeys]];
//NSLog(#"psc model:%#", pscModel);
//NSLog(#"psc keys:%#", pscKeys);
NSLog(#"psc contains %d entities", [pscModel.entities count]);
// Get the entity hashes from the storeURL
NSDictionary *storeMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType
URL:storeURL
error:&error];
NSDictionary *storeHashes = [storeMetadata objectForKey:#"NSStoreModelVersionHashes"];
//NSLog(#"store metadata:%#", sourceMetadata);
NSLog(#"store URL:%#", storeURL);
NSLog(#"store NSStoreUUID:%#", [storeMetadata objectForKey:#"NSStoreUUID"]);
NSLog(#"store NSStoreType:%#", [storeMetadata objectForKey:#"NSStoreType"]);
NSSet *storeKeys = [NSSet setWithArray:[storeHashes allKeys]];
// Determine store entities that were added, removed, and in common (to/with psc)
NSMutableSet *addedEntities = [NSMutableSet setWithSet:pscKeys];
NSMutableSet *removedEntities = [NSMutableSet setWithSet:storeKeys];
NSMutableSet *commonEntities = [NSMutableSet setWithSet:pscKeys];
NSMutableSet *changedEntities = [NSMutableSet new];
[addedEntities minusSet:storeKeys];
[removedEntities minusSet:pscKeys];
[commonEntities minusSet:removedEntities];
[commonEntities minusSet:addedEntities];
// Determine entities that have changed (with different hashes)
[commonEntities enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) {
NSData *storeHash = [storeHashes objectForKey:key];
NSEntityDescription *pscDescrip = [pscEntities objectForKey:key];
if ( ! [pscDescrip.versionHash isEqualToData:storeHash]) {
if (storeHash != nil && pscDescrip.versionHash != nil) {
[changedEntities addObject:key];
}
}
}];
// Remove changed entities from common list
[commonEntities minusSet:changedEntities];
if ([commonEntities count] > 0) {
NSLog(#"Common entities:");
[commonEntities enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) {
NSData *storeHash = [storeHashes objectForKey:key];
NSEntityDescription *pscDescrip = [pscEntities objectForKey:key];
NSLog(#"\t%#:\t%#", key, pscDescrip.versionHash);
}];
}
if ([changedEntities count] > 0) {
NSLog(#"Changed entities:");
[changedEntities enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) {
NSData *storeHash = [storeHashes objectForKey:key];
NSEntityDescription *pscDescrip = [pscEntities objectForKey:key];
NSLog(#"\tpsc %#:\t%#", key, pscDescrip.versionHash);
NSLog(#"\tstore %#:\t%#", key, storeHash);
}];
}
if ([addedEntities count] > 0) {
NSLog(#"Added entities to psc model (not in store):");
[addedEntities enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) {
NSEntityDescription *pscDescrip = [pscEntities objectForKey:key];
NSLog(#"\t%#:\t%#", key, pscDescrip.versionHash);
}];
}
if ([removedEntities count] > 0) {
NSLog(#"Removed entities from psc model (exist in store):");
[removedEntities enumerateObjectsUsingBlock:^(NSString *key, BOOL *stop) {
NSData *storeHash = [storeHashes objectForKey:key];
NSLog(#"\t%#:\t%#", key, storeHash);
}];
}
BOOL pscCompatibile = [pscModel isConfiguration:nil compatibleWithStoreMetadata:storeMetadata];
NSLog(#"Migration needed? %#", pscCompatibile?#"no":#"yes");
return pscCompatibile;
}
usage: called before adding each store to NSPersistentStoreCoordinator :
[self comparePersistentStore:self.psc withStoreURL:self.iCloudStoreURL];
_iCloudStore = [self.psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:self.iCloudStoreURL
options:options
error:&localError];
Every time you making change to the Core Date definition, you should delete the apps installed on the physical device or simulator.
Stop app from running.
Delete app on simulator.
Product - > Clean
Build, run.
The simplest solution that worked for me in Swift 2.1, Xcode 7 is :
Delete the app from the Simulator ( Cmd + Shift + H to go to the Home Screen. Long Press the app, Click cross, just the usual way you delete an app from your phone)
Cmd + Shift + H again to stop the dancing of apps
Go back to your project and rerun
I had this issue while writing/reading from Core Data with 2 entities set up. Deleting the app and rerunning the program fixed the issue
I just deleted [Simulator App Folder]/Document/*.sqlite file after making changes in entities and it worked.
And of course, .sqlite file contains all stored data and structures which will be lost.
Please Delete a application from simulator and clean a code and run .its work fine .do it may be its help YOU.
If you are using Swift.
Follow the answer by #Stas and insert options, in place of nil, in your App Delegate:
let myOptions = [NSMigratePersistentStoresAutomaticallyOption: true,
NSInferMappingModelAutomaticallyOption: true]
if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: myOptions, error: &error) == nil {
Try "Reset Content & Settings" in the simulator. Worked for me after deleting app and Clean build
I experienced the same issue with my app (not yet released in App Store).
Here's how I fixed it:
Run Clean (Cmd+Shift+K)
Restart iOS Simulator
iOS Simulator -> Reset Content and Settings (from navbar)
(3) was the step that finally got it to run properly. Hope this helps!
In my case, I had two persistent stores, one local store for user specific data, and one CoreData+CloudKit store for common data that syncs automatically with iCloud. Thus the data model has two configurations, and the entities are assigned to both configurations as required.
Due to a bug during development, I tried to store an entity that was no longer assigned to any configuration. So when the context was saved, CoreData realized the incompatibility, and crashed with this error.
Of course, deleting the app does not help in such a case. One has to ensure that only assigned entities are stored in a persistent store.
Although sometimes you can just remove the app from the device when changing schema in managed object model, in some scenarios this is not possible e.g. because you already published your app with an old schema.
If this is the case, you have to take care of migrating old data to the new schema:
Core Data Model Versioning and Data Migration
You'll need to migrate the Core Data model using migration. Any time you change the model, you make it incompatible without versioning. Strap yourself in, it's a bit of a hairy topic.
http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/CoreDataVersioning/Articles/Introduction.html
If you make changes to your Core Data model, you have to provide a migration policy that tells Core Data how to adopt existing persisted objects (that your users created with the currently released version) to the new model.
For some scenarios, Core Data is able to automatically infer the mapping from the old model to the new one. For more complex changes, you might have to implement some logic that performs the migration.
Details can be found in the Core Data Model Versioning and Data Migration Programming Guide.
Update
This answer here on Stack Overflow covers the basics of Core Data's lightweight migration and also has some code to get you started.
First, the only things that should be in the xcdatamodeld bundle are xcdatamodel files. Your subclasses should NOT be in the xcdatamodeld. Move those out of there. There is a fair chance they are confusing the compiler.
Second, the error indicates that Core Data cannot find your model. Have you created data and then touched the model? If so you are in an inconsistent state and need to fix that either by deleting the data (which Philippe suggested) or by rolling your changes of the model BACK.
This issue generally occurs due to incompatibility between the version on which DB has been created. General approach to this problem is to delete the app and reinstall it. But in your mentioned case the version of DB are completely different on Xcode 3.2 and 4.2. So better use same version of Xcode for DB.
I was getting the error but the reason I was getting the error was because of the following.
I originally had one Entity named "Entry" and had one row saved for that entity in the database. I then added another Entity named "Person" and after adding that went to build and got the error. So I solved the issue by deleting "Person" Entity and then building the app, deleted the row that was in "Entry" and then closed the application. I then deleted the app entirely off my phone and then did a rebuild and it worked fine. Not sure which step corrected the problem (the deletion of the row or the app), but hopefully if you're looking for a solution this will help. :)
Edit: Oh and if you worried about deleting your new Entity (in my case "Person") to build the app again remember you can get it back afterwards by using CMD+Z!
I had this problem - I first reset my simulator and then clean the project and rebuild. And then it works.
When you change core data, ( adding a field to table , removing field etc ), the sqlite file in applications document folder needs to be in sync with your schema.
This file is not overwritten by default, this file needs to be regenerated.
Follow these steps:
Go to the folder pointed by NSURL. (This path can be found in exception message generated by application before crashing.)
example : /Users//Library/Application Support/iPhone Simulator//Applications//Documents
remove or rename the sqlite file
Clean and Rerun the application
Rerunning application would generate a new sqlite file.
This will make sure that the schema and Xcode are in sync.
This may help some people but may not answer the question. In my case, the problem was solved because I forgot to add the model to the correct configuration. See the screenshot attached. All the models are added to the default configuration, but my application uses the private configuration. Drag and drop your model from the default configuration to the correct configuration.
iOS Simulator -> Reset Contents and Settings...
Worked for me
iOS Simulator -> Reset Contents and Settings... -> Reset
Works on iOS9 (xcode 7.1) as well

Saving Modified Data in CloudKit

I have been testing out CloudKit as i wish to release an app using it when the release of iOS8 occurs. It seems simple enough to save data using the code below:
CKRecordID * recordID = [[CKRecordID alloc] initWithRecordName:#"basicRecord"];
CKRecord * record = [[CKRecord alloc] initWithRecordType:#"basicRecordType" recordID:recordID];
[record setValue:#"defaultValue" forKey:#"defaultKey"];
CKDatabase *database = [[CKContainer defaultContainer] publicCloudDatabase];
[database saveRecord:record completionHandler:^(CKRecord *record, NSError *error) {
if (error) {
NSLog(#"Error: %#", error);
} else {
NSLog(#"Record Saved!");
}
}];
and I receive no errors from this. However, if i try to run the code again, maybe because i have changed the record value to
[record setValue:#"newValue" forKey:#"defaultKey"];
I receive an error which begs the question, how do i go about saving a modified piece of data. After all, this is a fundamental part of saving things to the cloud. The error is below and any help would be greatly appreciated, don't hesitate to ask for further information.
Error: <CKError 0x17024afb0: "Server Record Changed" (14/2017); "Error saving record <CKRecordID: 0x144684a80; basicRecord:(_defaultZone:__defaultOwner__)> to server: (null)"; uuid = 182C497F-966C-418A-9E6A-5563BA6CC6CD; container ID = "iCloud.com.yourcompany.CloudKit">
This error is probably because saveRecord: works only for new records or records that are newer than the version on the server:
This method saves the record only if it has never been saved before or if it is newer than the version on the server. You cannot use this method to overwrite newer versions of a record on the server. CKDatabase docs
The recommended approach to modify an existing record (or set of records) is to use a CKModifyRecordsOperation set with the desired savePolicy to deal with conflicts:
After modifying the fields of a record, use this type of operation object to save those changes to a database. (...)
When saving records, the value in the savePolicy property determines how to proceed when conflicts are detected on the server. CKModifyRecordsOperation docs
From the docs of CKRecord:
New records exist only in memory until you explicitly save them to iCloud.
When you set the new value [record setValue:#"newValue" forKey:#"defaultKey"]; you have already saved the record, making it invalid.
You can use CKModifyRecordsOperation and in most situations it might be preferrable but you don't have to. Just fetch your data using a fresh CKRecord, then feed that record into saveRecord: as described here.
After you save the record, fetch it so that the retured record will then have the RecordID that Cloudkit added
Then on that same fetched record, use setValue to change the data you want to change
Then you can use CFModifyRecordsOperation
In the example below, cachedCKRecordsServiceCenter contains the fetched records from cloudkit and those records have the CloudKit RecordID's in them......
//find this service center in the cached records
for (_,serviceCenter) in (theModel?.cachedCKRecordsServiceCenter.enumerated())! //is data for logged in Co ONLY with NO Co name attached
{
let name = serviceCenter["name"] as! String
returnValue = "Try Again"
if name == displayedRecordName
{
serviceCenter.setValue(displayedRecordName! + "_" + (theModel?.companyName)!, forKey: "name") //db values have Co name appended
serviceCenter.setValue(label2Text.text, forKey:"street1")
serviceCenter.setValue(label3Text.text, forKey:"street2")
serviceCenter.setValue(label4Text.text, forKey:"city")
serviceCenter.setValue(label5Text.text, forKey:"state")
serviceCenter.setValue(label6Text.text, forKey:"zip")
serviceCenter.setValue(label7Text.text, forKey:"phone")
serviceCenter.setValue(label8Text.text, forKey:"email")
serviceCenter.setValue(label9Text.text, forKey:"note")
let saveRecordsOperation = CKModifyRecordsOperation()
var ckRecordsArray = [CKRecord]()
// set values to ckRecordsArray
ckRecordsArray.append(serviceCenter)
saveRecordsOperation.recordsToSave = ckRecordsArray
saveRecordsOperation.savePolicy = .ifServerRecordUnchanged
appDelegate.locked = true
saveRecordsOperation.modifyRecordsCompletionBlock = { savedRecords, deletedRecordIDs, error in
if error != nil {
// Really important to handle this here
////////print("ERROR: Unable to update Driver Location: Error= \(error)")
self.returnValue = "ERROR: Unable to update Driver Location: ERROR = \(error)"
self.appDelegate.locked=false
}
else
{
////print("Successfully updated Service Center")
self.appDelegate.locked=false
self.returnValue = "Successfully updated Service Center"
self.appDelegate.locked=false
//reget the data into the cach
self.theModel?.fetchServiceCenterFromCloudKit1()
}
}
CKContainer.default().publicCloudDatabase.add(saveRecordsOperation)
}
}

Restkit 0.20 CoreData error "Can't find model for source store"

I am trying to configure RestKit with CoreData. I get and error with "Can't find model for source store". I was using the configurations from the Restkit RKTwitterCoreData example. I found some similar posts on stack overflow where people say to delete the database but I don't know how to do this, am running on my phone, not the simulator. I also tried to do a Product:Clean but same error.
2014-05-18 12:29:16.489 What my life could be[7006:60b] I restkit:RKLog.m:34 RestKit logging initialized...
2014-05-18 12:29:17.259 What my life could be[7006:60b] *** Assertion failure in -[AppDelegate application:didFinishLaunchingWithOptions:], /Users/Pro/Desktop/ios app/What my life could be/What my life could be/AppDelegate.m:161
2014-05-18 12:29:17.262 What my life could be[7006:60b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Failed to add persistent store with error: Error Domain=NSCocoaErrorDomain Code=134130 "The operation couldn’t be completed. (Cocoa error 134130.)" UserInfo=0x15d7fc40 {URL=file:///var/mobile/Applications/2E1DA997-E54E-4CE3-AC62-6552445D77CF/Documents/JustD.sqlite, metadata={
NSPersistenceFrameworkVersion = 479;
NSStoreModelVersionHashes = {
ActivityEntity = <fdd7d538 648131cf 2fe3b684 bd55169e 85a7cee4 cbec3080 94202e4c 26b97889>;
PriorityEntity = <74cd93d0 00ade70c ef4d0ea3 f177762d 7d342720 7aba6945 d83ee02d 96a2135c>;
UserDataEntity = <2ffd8aec e7c1dacc 23e14fdd 400b60c0 5a1cd9a8 07fe6138 4d0e5a30 8e0c6e28>;
};
NSStoreModelVersionHashesVersion = 3;
NSStoreModelVersionIdentifiers = (
""
);
NSStoreType = SQLite;
NSStoreUUID = "B1BC3FFF-F727-49E4-A44F-5C5216C58226";
"_NSAutoVacuumLevel" = 2;}, reason=Can't find model for source store}'
*** First throw call stack:(0x2ec07e83 0x38f646c7 0x2ec07d55 0x2f5b00af 0xf37bb 0x313fcaad 0x313fc4f3 0x313f6b41 0x31391a07 0x31390cfd 0x313f6321 0x3387676d 0x33876357 0x2ebd2777 0x2ebd2713 0x2ebd0edf 0x2eb3b471 0x2eb3b253 0x313f55c3 0x313f0845 0xf3bc5 0x3945dab7)
libc++abi.dylib: terminating with uncaught exception of type NSException(lldb)
The part of code to config the store. I deleted the CoreData template default code, got error both ways. Note: I am not sure how the "importer importObjectsFromItemAtPath:...." works.
#ifdef RESTKIT_GENERATE_SEED_DB
RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelInfo);
RKLogConfigureByName("RestKit/CoreData", RKLogLevelTrace);
NSError *error = nil;
BOOL success = RKEnsureDirectoryExistsAtPath(RKApplicationDataDirectory(), &error);
if (! success) {
RKLogError(#"Failed to create Application Data Directory at path '%#': %#", RKApplicationDataDirectory(), error);
}
NSString *seedStorePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:#"JustDid.sqlite"];
RKManagedObjectImporter *importer = [[RKManagedObjectImporter alloc] initWithManagedObjectModel:managedObjectModel storePath:seedStorePath];
[importer importObjectsFromItemAtPath:[[NSBundle mainBundle] pathForResource:#"activities" ofType:#"json"]
withMapping:activityMapping
keyPath:#"activity"
error:&error];
[importer importObjectsFromItemAtPath:[[NSBundle mainBundle] pathForResource:#"users" ofType:#"json"]
withMapping:userMapping
keyPath:#"user"
error:&error];
BOOL success = [importer finishImporting:&error];
if (success) {
[importer logSeedingInfo];
} else {
RKLogError(#"Failed to finish import and save seed database due to error: %#", error);
}
// Clear out the root view controller
[self.window setRootViewController:[UIViewController new]];
#else
/**
Complete Core Data stack initialization
*/
[managedObjectStore createPersistentStoreCoordinator];
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:#"JustD.sqlite"];
NSString *seedPath = [[NSBundle mainBundle] pathForResource:#"RKSeedDatabase" ofType:#"sqlite"];
NSError *error;
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:seedPath withConfiguration:nil options:nil error:&error];
NSAssert(persistentStore, #"Failed to add persistent store with error: %#", error);
// Create the managed object contexts
[managedObjectStore createManagedObjectContexts];
// Configure a managed object cache to ensure we do not create duplicate objects
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
#endif
It looks like you have changed the version of your core data model and not asked core data to try to migrate automatically or provided a migration explicitly. So, as core data loads it detects the version mismatch and aborts.
Initially, delete the app from your device and reinstall and everything should work again. You would need to do this each time you change the data model.
Obviously it isn't a good idea to go to the App Store like that so you should research auto migration and it's constraints and (if required) explicit migration.
To delete the database, just remove the sqlite file which should be at the address /var/mobile/Applications/2E1DA997-E54E-4CE3-AC62-6552445D77CF/Documents/JustD.sqlite
considering you logs
In a console:
rm /var/mobile/Applications/2E1DA997-E54E-4CE3-AC62-6552445D77CF/Documents/JustD.sqlite
Have you ensured your seed database is added to the Build Phase : Copy Bundle Resources?
I've just had the same problem for hours, and in the end it was as simple as that. Even though looking in the simulator-deployed app package, the seed sqlit file was there, but for some reason the managedObjectStore couldn't find it, but returned the “Can't find model for source store” error rather than, "Cannot find the seed data file" which would have been more helpful!

Cannot update object that was never inserted

I create an category object and save it:
NSManagedObjectContext *managedObjectContext = [[FTAppDelegate sharedAppDelegate] managedObjectContext];
_category = (Category *)[NSEntityDescription
insertNewObjectForEntityForName:#"Category"
inManagedObjectContext:managedObjectContext];
NSError *error = nil;
[managedObjectContext save:&error];
if (error) {
NSLog(#"error saving: %#",error);
}
then edit the name of the category object and save again.
_category.name = _nameTextField.text;
NSManagedObjectContext *managedObjectContext = [[FTAppDelegate sharedAppDelegate] managedObjectContext];
NSError *error = nil;
[managedObjectContext save:&error];
if (error) {
NSLog(#"error saving: %#",error);
}
and get this error:
2013-01-12 17:53:11.862 instacat[7000:907] Unresolved error Error Domain=NSCocoaErrorDomain Code=134030 "The operation couldn’t be completed. (Cocoa error 134030.)" UserInfo=0x2027b300 {NSAffectedObjectsErrorKey=(
"<Category: 0x1ed43cf0> (entity: Category; id: 0x1ed52970 <x-coredata://68E5D7B6-D461-4962-BC07-855349DB3263-7000-00000141BAB4C399/Category/tE8AB2F2E-C14C-4E93-8343-CC245B7726622> ; data: {\n categoryId = nil;\n isPrivate = 0;\n name = techies;\n users = (\n );\n})"
), NSUnderlyingException=Cannot update object that was never inserted.}, {
NSAffectedObjectsErrorKey = (
"<Category: 0x1ed43cf0> (entity: Category; id: 0x1ed52970 <x-coredata://68E5D7B6-D461-4962-BC07-855349DB3263-7000-00000141BAB4C399/Category/tE8AB2F2E-C14C-4E93-8343-CC245B7726622> ; data: {\n categoryId = nil;\n isPrivate = 0;\n name = techies;\n users = (\n );\n})"
);
NSUnderlyingException = "Cannot update object that was never inserted.";
}
Thank you for your time and consideration.
I am using the AFIncrementalStore.
How about something like this:
self.category.name = self.nameTextField.text;
NSManagedObjectContext *managedObjectContext = [[FTAppDelegate sharedAppDelegate] managedObjectContext];
if(![self.category isInserted])
{
[managedObjectContext insertObject:self.category];
}
NSError *error = nil;
[managedObjectContext save:&error];
if (error) {
NSLog(#"error saving: %#",error);
}
Basically check the object is it has been inserted before, if not, insert it and then save the context.
When you update an object, you can't use insertNewObjectForEntityForName, you need to first save your object, then call something like
[self.managedObjectContext refreshObject:_category mergeChanges:YES]
Then use managedObjectContext save again.
This is the difference in direct SQL as "INSERT" and "UPDATE".
Your object is loosing the managedObjectContext. Either use
self.managedObjectContext
or refetch the object in
[[FTAppDelegate sharedAppDelegate] managedObjectContext]
and edit the refetched object and then save it.
I have the same error but different and rare scenario, it happens once in almost 100 attempts. Find my problem below:
I have 2 NSManagedObjects in core data model:
1- Lead
2- LeadAttirbute
Lead has 1-M relationship with LeadAttribute.
There is a form that inputs for lead and refresh(create new lead) the form after submitting a lead. If i keep on submitting the leads then at a stage, [managedObjectContext save:&error]; starts giving below error:
Domain=NSCocoaErrorDomain Code=134030 "The operation couldn’t be completed. (Cocoa error 134030.)" UserInfo=0x1f251740 {NSAffectedObjectsErrorKey=(
" (entity: LeadInfoAttribute; id: 0x1f2eb920 ; data: {\n attributeId = 0;\n lead = nil;\n optional = nil;\n orderId = 0;\n title = nil;\n value = Bjjbjp;\n})"
), NSUnderlyingException=Cannot update object that was never inserted.}
And it keeps on giving the same error until i dont terminate and re-launch the app. I'm not able to update anything in core data model after this error occur, So my questions are:
1- Can we remove the fault state of core data? i.e to capture and delete the object that is creating trouble before making the save call again.
2- What could be the possible reasons for this issue? Since its very rare and can't reproduce this everytime.
I've just run into this issue and in my case the problem was following:
1) create new managed object in context A
2) save the context A
3) retrieve this object by objectID from context B
4) make changes on managed object and save the context B
Normally it wouldn't be a problem, but in this case the context A is child context and therefore doesn't save to persistent store (just to parent context, which isn't the context B). So when fetch for managed object is done from context B, context doesn't have this object. When changes are made, context tries to save them anyway...and thats when this error occurs. In some cases (as #Trausti Thor mentioned) the refreshObject:mergeChanges: method could help (it passes the data to another context).
In Your case I'll check if:
1) managed object context from [[FTAppDelegate sharedAppDelegate] managedObjectContext] returns always the same context
2) when you save the category, check if it was really saved to persistent store (self.category.objectID.isTemporaryID == NO)
NOTE:
The second point is more important, because if you look carefully, your category object still has temporary objectID, that means it's not persisted.
What I think it's happening is that you are not getting the right NSManagedObjectContext.
Think about it as a session. So when you update you are not getting the right session and so your object doesn't exist there.
Before doing the second save try to find your object on that NSManagedObjectContext.
If you need further help please describe what happens between the creation and the update.
Getting the wrong NSManagedObjectContext can be due to bad code on the AppDelegate or accessing from another thread other than the main thread.

MagicalRecord: multiple databases

I have an app that uses MagicalRecord, and I'm pre-populating the database with a large amount of data that is used for reference. Within that same data model, I have user-definable information pertaining to things the user may do in the app.
The app was rejected because the pre-populated data is supposed to be marked as "do not backup". So, I'd like to have that data in a separate datastore so that I can keep the user data as backupable.
Is there a way to have two separate datastores using MagicalRecord?
I think it's possible, but not too easy though.
As you know, to work with more than one database, you should bring some changes to your PersistentStoreCoordinator, so it will have two PersistentStores. After this, you Core Data stack would look like this:
The other way is two make two separate PersistentStoreCoordinators, each carrying one store.
In Magical Record, there are several class methods for adding stores in
NSPersistentStoreCoordinator+MagicalRecord.h.
(NSPersistentStore *) MR_addInMemoryStore;
(NSPersistentStore *) MR_addAutoMigratingSqliteStoreNamed:(NSString *) storeFileName;
(NSPersistentStore *) MR_addSqliteStoreNamed:(id)storeFileName withOptions:(__autoreleasing NSDictionary *)options;
I think, that this is the place where you could do the thing you want.
Also i should mention, that the whole proccess of setting up the stack goes in MagicalRecord+Setup.h
+ (void) setupCoreDataStackWithStoreNamed:(NSString *)storeName
So you can add your Stores and Coordinators there.
I've never managed it by myself, that was just a brief investigation of a possible solution.
I was able to solve this issue using configurations. Since Magical Record always sends null for the configuration parameter, I broke apart setupCoreDataStackWithAutoMigratingSqliteStoreNamed and replaced it with a method that supports multiple configurations.
Because Magical Record does a good job of handling auto migrations, I first call setupCoreDataStackWithAutoMigratingSqliteStoreNamed, followed by cleanup, and then I supply my replacement code.
I have one object model with my seed data objects assigned the the "Seed" configuration and user objects assigned to the "User" configuration. Magical Record has already been initialized so it could auto migrate if necessary.
+(void) RB_setupMultipleStores:(NSString *) seedStoreName userStore:(NSString *) userStoreName
/* change persistent store to one with multiple configurations. Assumes Magical Record is initialized. */
{
NSError * error= nil;
[MagicalRecord cleanUp];
NSManagedObjectModel * model = [NSManagedObjectModel MR_defaultManagedObjectModel];
NSURL *seedURL = [NSPersistentStore MR_urlForStoreName:[seedStoreName stringByAppendingString:#".sqlite"]];
NSPersistentStoreCoordinator * coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
nil];
NSPersistentStore * seedStore =[coordinator
addPersistentStoreWithType:NSSQLiteStoreType
configuration:#"Seed"
URL:seedURL
options:options
error:&error];
if (!seedStore || error)
{
NSLog(#"Error setting up seed store:%# for %#", [error localizedDescription], seedURL);
exit(-1);
}
NSURL *userURL = [NSPersistentStore MR_urlForStoreName:[userStoreName stringByAppendingString:#".sqlite"]];
NSPersistentStore * userStore = [coordinator
addPersistentStoreWithType:NSSQLiteStoreType
configuration:#"User"
URL:userURL
options:options
error:&error];
if (!userStore || error)
{
NSLog(#"Error setting up user store:%# for %#", [error localizedDescription], userURL);
exit (-1);
}
[NSPersistentStoreCoordinator MR_setDefaultStoreCoordinator:coordinator];
[NSManagedObjectContext MR_initializeDefaultContextWithCoordinator:coordinator];
}
Also, MR 3.0 has concurrent stacks which may solve the problem once it is done.
Keeping data for different Core Data entities in different store files is well supported and fairly straightforward. However, MagicalRecrd doesn't provide any convenience methods for setting up your Core Data stack in this way. You simply have to allocate your stack manually, and tell MagicalRecord to use the NSPersistentStoreCoordinator you create. Here's how I did it in swift:
import Foundation
import CoreData
import MagicalRecord
class CoreDataSetup {
static func setupAutoMigratingStack(withContentConfigurationName contentConfigurationName: String, userConfirgurationNameName: String) {
MagicalRecord.cleanUp()
let managedObjectModel = NSManagedObjectModel.MR_defaultManagedObjectModel()
let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel!)
let contentURL = NSPersistentStore.MR_urlForStoreName(contentConfigurationName + ".sqlite")
let userURL = NSPersistentStore.MR_urlForStoreName(userConfirgurationNameName + ".sqlite")
let options = [
NSMigratePersistentStoresAutomaticallyOption : true,
NSInferMappingModelAutomaticallyOption: true,
NSSQLitePragmasOption: ["journal_mode": "DELETE"]
]
do {
try persistentStoreCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: contentConfigurationName, URL: contentURL, options: options)
try persistentStoreCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: userConfirgurationNameName, URL: userURL, options: options)
NSPersistentStoreCoordinator.MR_setDefaultStoreCoordinator(persistentStoreCoordinator)
NSManagedObjectContext.MR_initializeDefaultContextWithCoordinator(persistentStoreCoordinator)
} catch {
print("Error adding persistent store to coordinator: \(error) ")
}
}
}
Note that in my code I'm referring to your concept of the "seed" store as "content" and the user-definable store as "user".
To accomplish the second aspect of your question, configuring the content store to not be backed up, you simply have to play around with the URLs where you store each store, placing the content store in a non-backed up temporary directory, and copying it to that location up launch from your app bundle if it doesn't exist.

Resources