Core Data, No Inverse Relationship - ios

I'm working to get rid of a bunch of warnings in our codebase of the form:
Entity.relationship should have an inverse.
In general, although our code does not reach through these inverses, it sounds like it is a good idea to put them in anyway.
My question is about how I would do this.
Should I make these changes through a lightweight migration? That is, should I be creating another xcdatamodel?
For the given data model, what if we already have multiple versions/migrations. For example supposed we have the ReportsDataModel. And underneath that are ReportsDataModel1, ReportsDataModel2, and ReportsDataModel3. It seems like XCode 7 is giving me the same warnings on each data model. So if I fixed them in a lightweight migration to ReportsDataModel4, it seems like it wouldn't get rid of the previous warnings.
What is the recommended way to get around this issue?
-Arjun

First of all, you would be correct that you should implement the inverse relationships, as Xcode requires them. It's a good database practice, and you can virtually ignore the excess relationships if you're not using them.
Yes, you should be able to perform a lightweight migration, that is, create a new data model and let Xcode infer the changes. Here, Apple states that lightweight migration supports adding relationships.
Regarding your second question, true, creating another data model will not actually solve the warning in the older ones. You must leave the older models in Xcode so it can compute the lightweight migration process. If you erase a model and a user updates from an older version that uses that model, their data will be corrupted. (However, if you haven't published a version of the app with a particular data model, you can delete that data model.)
However, you can try suppressing the inverse relationship warning entirely.
In Xcode, click on your project file.
Click the Build Settings tab.
Search for MOMC.
Set Suppress momc warnings on missing inverse relationships to Yes.
EDIT about getting rid of the warnings on only the old models: This question suggests that you could move the old data model out of Xcode and place it elsewhere, and add a Copy Files action to Build Phases to copy the file back in at compile time. This way the file and it's extraneous warnings could be out of your way. Sorry there isn't a less "hacky" solution.

Related

When should I increase xcdatamodeld version?

someone please explain when should I increase the xcdatamodeld version? I google a lot, there are all about migration, but when should I increase the version?
Currently if I make change in my xcdatamodeld such as add entity or add attribute, I will recreate nsmanagedobject subclass. But I am not sure what situation that I have to increase the xcdatamodeld version.Please someone explain it. Thanks!
I think of it as a tool for helping users of my app migrate from the previous data model to the new data model. So I don't bump the version up unless I have to "release" it in some fashion (app store, or internal testers). Even then, if I have a small group of testers, I may just tell them to delete and reinstall so that I don't have to muck with it.
If a user with the old data model installs your app update with a new data model, they will crash unless you instruct the data model to "migrate".

Better way to recreate the class definition after modifying core data model?

When designing the core data model in XCode, you can automatically generate NSManagedObject subclass definitions (.m and .h files) by
Selecting the Entities
Choosing "Create NSManagedObject Subclasses" from EDITOR menu
After that, you may add a lot of code in these classes, what if you have to modify the data model setting a lot for some reason after that? To reflect these changes on the data model, is there any automatic way to do that? or you have to do everything manually.
Currently if I try to recreate these class definition from EDIT menu again(automatically), it will replace all the current files. All added code will disappear.
I really hope future version of Xcode can add a smart feature: automatically updating the default class definition without losing the added work. Maybe I am too lazy. :)
You're running into a common problem. You're pretty much stuck with that way of creating managed object subclasses with Xcode for the time being. Knowing that, you can either:
Design around it
For simple cases, you can use Categories to add functionality (though not state) to your NSManagedObject subclasses. Code in the category's file is obviously safe from being overwritten every time your data model changes.
Don't use Xcode
Mogenerator is a nifty tool designed to solve exactly that problem. It creates two classes for each entity instead of one, allowing Xcode to manage one while you manage the other.
It seems Apple has addressed the issue with XCode 7 : now it automatically creates the entity and a category of the entity with its core data properties. When you regenerate, it only updates the category, leaving your custom code in the entity class unharmed. See this link
You can create a class with different name and paste the generated fields into the old class

Coredata inferred mapping model is failing on my old databases

I'm using CoreData for one of my databases, and I'm having trouble with an upgrade to my App.
My old databases are no longer loading ... I get the error "Cocoa error 134190" which I believe means that the inferred mapping model is failing.
When I started editing this version of my App, I created a new model version, and I simply added one new attribute to one entity, and two new attributes to another entity. Nothing was changed or deleted.
I've checked inside my App's directory, and all of the model versions are there.
I even have a snapshot of my previous version of the App, and with that snapshot I can load my core data files.
To debug what is going wrong, I took the exact data model from my previous snapshot and used it in my current version, and I still get the error.
I've even done a "diff" on every file in my ".app" directory packages, and there are only two files that are different between the two. One is the actual binary for the application, and the other is the "Info.plist" file. I looked at the Info.plist files, and they too are basically identical (the new one has a newer bundle version, but no other change).
Any idea why the inferred mapping is broken?
I am getting the same error even when the data models are completely unchanged from my last version which works.
This is extremely frustrating.
Any information as to how to track down problems like this in the future would also be greatly appreciated!!!
I found the answer ... the problem was that in my new version, I was rearranging the locations of my files. I did so by simply moving the database to a new location. What I didn't realize is that coredata databases have some knowledge of their path built in, and you can't simply move them.
I needed to change the location of the database using the NSPersistentStoreCoordinator's method:
migratePersistentStore:toURL:options:withType:error:
My fault, but I really wish that core data error messages weren't so cryptic.
In the next version of my App, I'm going to remove core data completely.
Ron
I don't believe core data actually cares where the database file is, but I could be wrong. In the times I have seen this error, specifically "Cocoa error 134190" while trying to infer a model mapping, it's been the case that there was actually a problem trying to migrate to the next version of the model.
For example, when I found this thread today because I was helping someone with this problem, the real underlying issue was that the type of one of the attributes was accidentally changed. The automatic migration can't handle that sort of change.
A somewhat easy way to look at the changes between two model versions is to diff the description files themselves on the command line with diff:
diff yourNameHere.xcdatamodeld/yourNameHere5.xcdatamodel/contents yourNameHere.xcdatamodeld/yourNameHere4.xcdatamodel/contents
(That assumes you have a core data model description named "yourNameHere" and you're looking at a problem migrating from version 4 to 5. You'll have to adjust for your specific files.) In this diff you should see whatever additional things you've added, but you're really looking for something like a type changing when it shouldn't.

Using one xcdatamodelId in two app

I created one project with core data that will work with unchangeable database. And I don't want to write code in this project , that will programmatically populate this database. So, I create second project with core data, add existing xcdatamodel from first project without copying(only references). There i populate my database, open it with mozilla plug-in and it successfully filled. Then I copy ,my *.sqlite file and manually replace it with old file in first project. It causes error:"The model used to open the store is incompatible with the one used to create the store". But I use for both files the same xcdatamodelid. Where my error?
Sorry for my english, I really need help.
P.S. when I open sqlite file from first project and second (with commented code of populate base) in FileMerge - second is already empty. I appreciate any advice or help.
Karoly S nicely answers the question. I have a hint that I frequently employ that may prevent this out of sync situation. Instead of two Xcode projects trying to share one model file, just create one Xcode project with two targets. Each target will use the same model file, any class definitions derived from that model, and possibly other code. My second target is a Mac OS command line program that generates the database, while my first target continues to be the iOS app that reads that database. The Mac OS target will overwrite the database file in a project subdirectory, ensuring it's up-to-date. If I make any changes to the model, Xcode knows to update both targets.
Did you change your Model Definitions in any way? The error you are seeing is because there is some difference between the model from when you created it, and again from when you are trying to reference it. Are you running on the simulator? Try to delete both of your apps to clear the data related to it, as it might be out of date. Afterwards simply rebuild both of your projects as that will update your core data database.
EDIT: To clarify a bit more, your core data model is out of sync, this is generally caused by you building and running an app, and a database being created, then redefining your object model, this can be done in a variety of ways, most likely caused by the addition of an attribute or entity. So when you are trying to load the database there are fields that the app and core data are looking for, but are not there because they did not exist when the database was created. I hope this helps.

Core Data migration failing on Release builds only

I added an attribute to a Core Data model (iOS). I was on version 2, so I added a new model and saved the new attribute under version 3.
My loading code is standard (initializing a MOM using initWithContentsOfURL: pointing at my .momd directory inside my bundle), then passing that MOM to a NSPersistentStoreCoordinator.
Then, I download my app from the App Store, run it, and then try to test the migration. Lightweight migration is working fine on my Simulator and my phone in Debug (tethered to Xcode 4).
However, when I sync a Release build (using the "Archive" feature on Xcode) using iTunes, my app's data store fails to migrate with this error:
Error Domain=NSCocoaErrorDomain Code=134130 "The operation couldn’t be completed.
(Cocoa error 134130.)", reason=Can't find model for source store}
Worse yet, the store gets lost in some voodoo state where it cannot escape - if I re-tether the device and install a Debug build from Xcode again, I can't "recover" the migration.
The error message above omits the details about my entities. I can provide that if helpful, but any ideas on what might be wrong here? I've read just about every question on SO about this error code and so far all of them have failed to produce a result.
I tried a manual migration, but it also yielded an error. However, since I only added 1 attribute to 1 entity, it doesn't make sense that lightweight migration isn't working.
Every time I've seen this problem, in my code or someone else, it has been XCode getting into some kind of bad state with regards to the model versions it deploys in the application. Open the Release IPA archive of your app, and look at what mom files are in it. If you see one of the previous versions missing, that is likely this same problem. As for a solution, I've had mixed results; some variation of the following steps works for me, but never in a consistent order.
Clean & delete the derived data for the project (make sure you have an archive of your released app saved so you can symbolicate if necessary)
Rename the previous model version files (in xcode), adding or removing the space between the name and the digit representing the version number (if it has a space, replace with '_', if it doesn't have a space try adding one)
Add a new version of the model, without changing any of it's content, and make it the 'current' version
I know these steps seem like grasping at straws, which is exactly what it feels like whenever this happens to me. You might consider using one of your support incidents with Apple, it would be nice to know what their official answer to this issue is.

Resources