5

Can I use "Automatic Lightweight Migration" if my already release v1 didn't have a versioned Core Data model?

If yes, are there any key changed to the documented steps I need to apply?

Greg
  • 34,042
  • 79
  • 253
  • 454
  • have accepted this, but had an issue in terms of implementing which I thought probably goes in it's own question, so I've put it here... http://stackoverflow.com/questions/7624502/cant-find-model-for-source-store-occurring-during-iphone-automatic-lightweigh Would still appreciate any help on this one. – Greg Oct 02 '11 at 03:53

3 Answers3

6

Not only can you do this, in one sense it is the only way you can do this. From the Apple Documentation, "To create a versioned model, you start with a normal model..."

Your v1 had a normal model. As long as you have that model, and you follow the steps linked in that tutorial to create a versioned model, lightweight migration will work—if your migration meets the usual lightweight migration requirements. The lightweight migration happens in your v2 app (or in v1.1 or whatever). The data model that was in your v1 app essentially has no relevance. What Core Data needs is to find that the new v2 app has a copy of the data model that matches what is found in the Core Data store on the local device, and has a new data model that describes how you want the data to be stored from this point forward. If the changes required meet the requirements for lightweight migration, it then does it.

What are those requirements? From the Apple documentation on Lightweight Migration:

To perform a lightweight migration, Core Data needs to be able to find the source and destination managed object models itself at runtime. (Core Data searches the bundles returned by NSBundle’s allBundles and allFrameworks methods.) It must then analyze the schema changes to persistent entities and properties and generate an inferred mapping model. For Core Data to be able to do this, the changes must fit an obvious migration pattern, for example:

• Simple addition of a new attribute
• A non-optional attribute becoming optional
• An optional attribute becoming non-optional, and defining a default value.

If you rename an entity or property, you can set the renaming identifier in the destination model to the name of the corresponding property or entity in the source model. You typically set the renaming identifier using the Xcode Data Modeling tool, (for either an NSEntityDescription or an NSPropertyDescription object). In Xcode, the renaming identifier is in the User Info pane of the Detail Pane, below the version hash modifier (see The Browser View in Xcode Tools for Core Data). You can also set the identifier at runtime using setRenamingIdentifier:. For example, to handle

• Renaming of an entity Car to Automobile,
• and Renaming the Car’s color attribute to paintColor

you would include the following code after loading the destination data model, and before attempting to open a store file:

NSEntityDescription *automobile = [[destinationModel entitiesByName] objectForKey:@"Automobile"];
[automobile setRenamingIdentifier:@"Car"];
NSPropertyDescription *paintColor = [[automobile attributesByName] objectForKey:@"paintColor"];
[paintColor setRenamingIdentifier:@"color"];

In summary, you didn't miss the boat, and it's not too late to make use of these features of Core Data. :) And to answer your specific question, there is nothing you need to change from the standard steps outlined in the documentation.

Later update Further thoughts based on your comment to another answer, where you said:

so just to confirm, I don't have to in XCode back track my core data model to what it looked like a v1 and then version it then? So I can just create the first core data model version at the point where my application is at v2?

From what you are saying here, the issue would appear to be different to the initial question. Your initial question says that you have already released v1 of your app, without explicitly adding a versioned model. However, this statement implies that you have made changes to your core data model for v2 of your app, without first creating a versioned data model. This is quite a different thing.

If this is the case, then your job is more difficult. However, you can retrieve what you need presuming you keep backups of your source code or manage your code in a repository like git (and I would recommend all developers do both). If you've already changed your core data model for v2, what you need to do is turn the current data model into a versioned model, then restore/checkout a copy of v1 of your app, copy the core data model (the *.xcdatamodel file) from there into your current project, so that you then have both the v1 data model and your newer one. Then you will potentially be able to use lightweight migration, as discussed above.

Note that the key issue here is when you changed your data model. Whether your app is called v1 or v2 is essentially irrelevant to the question, other than obviously that it may be that you introduced changes to the data model at the same time you changed the version number to v2 of the app.

Duncan Babbage
  • 19,972
  • 4
  • 56
  • 93
  • thanks Duncan - mind if I clarify with you re "Core Data needs to be able to find the source and destination managed object models itself at runtime" - how would I check this re looking at my code? I really just copy/pasted the standard apple code re setting up the core data stuff. I'm sure it's probably ok, but from the point of learning I'd be interested in hearing the answer... – Greg Sep 29 '11 at 21:30
  • All that means is that in your application you keep both of the managed object models... that is, you don't make changes in the original one, but rather follow the instructions to create a versioned setup which includes duplicating your existing model and making changes to that. You then set your new model to be the new one. When the app launches, it sees that the model stored on the device/in the simulator does not match the current model. It then looks to see if there is another model, finds there is, and then applies any automatic migration it can between the two. Hence "find... itself". :) – Duncan Babbage Sep 30 '11 at 04:34
  • Reading your question more carefully... to clarify even more explicitly: there is nothing that you implement in code in order to facilitate this connection between source and destination models, and you don't have to change any of your code that accesses you data store like any fetched results controllers etc. You simply set up a new model, and Core Data infers the connection itself based on the presence of the two models, and the state of the data store on the device. If you can use lightweight migration, it's almost like magic... – Duncan Babbage Sep 30 '11 at 04:36
  • thanks Duncan - trying to get back onto this today to test & update – Greg Oct 01 '11 at 21:23
  • Added a version & updated some code per http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/vmLightweight.html#//apple_ref/doc/uid/TP40008426-SW1, however did not seem to work Duncan. Got "http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/vmLightweight.html#//apple_ref/doc/uid/TP40008426-SW1", reason=Can't find model for source store. – Greg Oct 01 '11 at 23:44
  • (cont) do you think I really need to revert to previous version of model only in Xcode, create a version 1, make changes, create a version 2, and then try? – Greg Oct 01 '11 at 23:45
  • Duncan - I'll accept this answer, but I am actually stuck on an issue in relation to getting this working, which I put in this question here http://stackoverflow.com/questions/7624502/cant-find-model-for-source-store-occurring-during-iphone-automatic-lightweigh – Greg Oct 02 '11 at 03:52
  • Thanks Ducan for your explanation. I have a query, how we can perform migration if we change type of an existing attribute? e.g. in v1 I have an entity E1 with attribute1 of type NSString and now I change type of this attribute1 to NSNumber/Boolean in v2 then how to implement this kind of migration. Thanks – iOS Monster Jul 24 '14 at 08:50
  • iOS Monster, storing a property in an NSNumber rather than an NSString can't be done with Lightweight Migration. You will need to define a Mapping Model that specifies how the migration is handled. It's not that complex. See this Apple documentation: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/vmMappingOverview.html#//apple_ref/doc/uid/TP40004399-CH5-SW1 – Duncan Babbage Jul 24 '14 at 22:53
3

Save off your current non-versioned model file (the .xcdatamodel package).

Now, create a new model version. You will have instead of a single .xcdatamodel package, a .xcdatamodeld file. Right click on it in Finder, select "show package contents". That opens it as a directory - drag your old .xcdatamodel file into that directory alongside the new versioned .xcdatamodel package.

Now an automatic migration should work if it's possible, you may not need a mapping model. Test to be sure though!!!

I have used this approach in a production application and it did work. As long as CoreData can find both the current model the app is using, and the model the new version of the model the application relies on it can attempt the automatic migration.

Kendall Helmstetter Gelner
  • 74,769
  • 26
  • 128
  • 150
1

yes it is possible because by creating the new version you can also create a version mapping file. This file tells the application which keys will be changed to which keys in the new version (and of course which one are deleted and created)

the apple documentation: http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/vmMappingOverview.html

  • so just to confirm, I don't have to in XCode back track my core data model to what it looked like a v1 and then version it then? So I can just create the first core data model version at the point where my application is at v2? – Greg Sep 25 '11 at 22:28
  • sorry I don't really understand the question. You have an app, using a CoreData storage already and now want to start versioning it. Am I right? yes you can start with your "v1" even if you had more versions before. (and thats what I did in my app. I didn't really needed migration in the first time, so I always deleted the old one and startet with a blank database) –  Sep 25 '11 at 22:34
  • 1
    It MAY be possible to use a mapping model without a v1 version of your database, but the one thing you would need to make this work is to store the unique UUID that represents your current database - every time you make a change to Core Data, it generates a new unique ID for that database version. Even just versioning without changing the model might create a new version. To start create a versioned model, keeping what you have, then cretae a new version and make changes, then create a mapping file - in there make sure the unique ID for the from DB is equal to what you currently have. – Kendall Helmstetter Gelner Sep 25 '11 at 23:25
  • @Kendall - thanks, but are you implying the "Automatic Lightweight Migration" won't work? Ie that one would need to create a mapping model... – Greg Sep 26 '11 at 02:07
  • I am pretty sure the automatic migration will not work if it cannot find a model for the current version. But I have another idea that I will post separately... – Kendall Helmstetter Gelner Sep 26 '11 at 03:03
  • ok - thanks Kendall...look forward to hearing what you had in mind – Greg Sep 26 '11 at 04:07