Understanding Versions

There are two distinct views of versioning: your perspective as a developer, and Core Data’s perspective. These may not always be the same—consider the following models.

Figure 1-1  Recipes models “Version 1.0”
Schema for Core Recipes application version 1.0
Figure 1-2  Recipes model “Version 1.1”
Schema for Core Recipes application version 1.1; added custom class for Recipe entity
Figure 1-3  Recipes model “Version 2.0”
Schema for Core Recipes application version 2.0

As a developer, your perspective is typically that a version is denoted by an identifier—a string or number, such as “9A218”, “2.0.7”, or “Version 1.1”. To support this view, managed object models have a set of identifiers (see versionIdentifiers)—typically for a single model you provide a single string (the attribute itself is a set so that if models are merged all the identifiers can be preserved). How the identifier should be interpreted is up to you, whether it represents the version number of the application, the version that was committed prior to going on vacation, or the last submission before it stopped working.

Core Data, on the other hand, treats these identifiers simply as “hints”. To understand why, recall that the format of a persistent store is dependent upon the model used to create it, and that to open a persistent store you must have a model that is compatible with that used to create it. Consider then what would happen if you changed the model but not the identifier—for example, if you kept the identifier the same but removed one entity and added two others. To Core Data, the change in the schema is significant, the fact that the identifier did not change is irrelevant.

Core Data’s perspective on versioning is that it is only interested in features of the model that affect persistence. This means that for two models to be compatible:

Notice that Core Data ignores any identifiers you set. In the examples above, Core Data treats version 1.0 (Figure 1-1) and 1.1 (Figure 1-2) as being compatible.

Rather than enumerating through all the relevant parts of a model, Core Data creates a 32-byte hash digest of the components which it compares for equality (see versionHash (NSEntityDescription) and versionHash (NSPropertyDescription)). These hashes are included in a store’s metadata so that Core Data can quickly determine whether the store format matches that of the managed object model it may use to try to open the store. (When you attempt to open a store using a given model, Core Data compares the version hashes of each of the entities in the store with those of the entities in the model, and if all are the same then the store is opened.) There is typically no reason for you to be interested in the value of a hash.

There may, however, be some situations in which you have two versions of a model that Core Data would normally treat as equivalent that you want to be recognized as being different. For example, you might change the name of the class used to represent an entity, or more subtly you might keep the model the same but change the internal format of an attribute such as a BLOB—this is irrelevant to Core Data, but it is crucial for the integrity of your data. To support this, Core Data allows you to set a hash modifier for an entity or property see versionHashModifier (NSEntityDescription) and versionHashModifier (NSPropertyDescription).

In the examples above, if you wanted to force Core Data to recognize that “Version 1.0” (Figure 1-1) and “Version 1.1” (Figure 1-2) of your models are different, you could set an entity modifier for the Recipe entity in the second model to change the version hash Core Data creates.