Select the project, data model, and entity for which you want to generate the interface.. When your new application attempts to access its old data, Core Data locates the previous data s
Trang 1CREATING AN INSTANT INTERFACE
Xcode can create an “ instant interface ” from a data model An instant interface produces a
functional Cocoa user interface that allows you to enter and edit data in your data model This can
be a huge time saver if you are just getting your application going or just need a minimal interface in
which to view or edit your data You often have some portion of a working data model, but no data
and little or nothing that resembles an application
To create an instant interface, you ’ ll fi rst need a window to put it in: open a nib document in
Interface Builder that already has a Cocoa window in it, create a new nib document, or add a new
window object to an existing nib document
You can now initiate the interface builder process from either Xcode or Interface Builder:
To use Xcode, arrange the window so that it is visible on the screen alongside your data model window in Xcode Switch back to the data model window Select the Pointer tool
While holding down the Option key, click and drag an entity from the data model diagram and drop it into the Interface Builder window When you start the drag, a shadow of the entity with a + sign follows the cursor If it does not, you are not dragging a copy
of the entity
To use Interface Builder, drag a Core Data Entity object (you ’ ll fi nd it in the Core Data group) from the library palette into the window A browser appears Select the project, data model, and entity for which you want to generate the interface
Xcode now asks you if you want an interface that represents one or many entity objects Entry
fi elds are created for each attribute For a collection of entities, Fetch, Add, and Delete buttons can
be created along with a table listing all of the instances in the collection Figure 15 - 16 shows the
instant interface created for many Faculty entities
➤
➤
FIGURE 15-16
Trang 2Amazingly, the entire interface is produced without any code The interface is constructed using bindings and Interface Builder connections If nothing else, it ’ s a testament to the power of bindings
A little time spent exploring these bindings can be very educational
MIGRATING DATA SCHEMAS
The problem with persistent data is that it is, well, persistent Data written to a data
fi le might exist for years, even decades, while your application continues to evolve Unless your data model is trivial, or you have exceptional foresight, a time will come when you need
to change your data model, such that the data model of your application no longer agrees with the structure of the existing database When this happens, your application is no longer able to read the previously written data The important thing to remember is this:
A data schema must agree with the format and organization of the information in the data
store Any discrepancies make the two inoperable
To help circumvent this inevitable disaster, Core Data supports data model versioning Instead of
simply changing your data model, you create a new one — a version When your new application attempts to access its old data, Core Data locates the previous data schema version, uses that to read the data, and then transitions the data from the old schema to the new one; a process called
data migration
Make backups of your existing (working) data stores before beginning any migration project You probably won ’ t get it right the fi rst time, which might leave you with an incorrectly migrated data store
This section describes the data modeling tools that let you confi gure versions, defi ne mappings between versions, and provide hints for Core Data to use during migration You should read
the Core Data Model Versioning and Data Migration Programming Guide for more in - depth
information, as well as the programmatic requirements
Core Data migration requires code to be added to your application; it won ’ t happen automatically, even after you ’ ve followed all of the steps in this section.
See the Core Data Model Versioning and Data Migration Programming Guide for the code needed to request or initiate a data migration
➤
Trang 3Creating a New Version
The fi rst step in any migration strategy is to
create a new version of your data schema With
your current data model open, or selected in the
source group, choose Design ➪ Data Model ➪
Add Model Version A copy of the model will
appear in your project, as shown in
Figure 15 - 17
If this is your fi rst alternate version, your
single data model document becomes a group
containing the original and all subsequent
versions This parallels the organization of localized
resources, which appear as a group containing their individual variants
When compiled, all of the versions will be combined into a single managed object model (mom)
bundle, providing your application with run time access to all versions One version is designated
as the current version, indicated by a check mark (see Figure 15 - 17) To change the current version,
open or select the desired data model document and choose Design ➪ Data Model ➪ Set Current
Version
Be careful not to build your data models twice When you create the fi rst new version of your data model, your mom document deployment changes from building a single .mom fi le to packaging multiple .mom fi les inside a nested .momd
bundle The .momd bundle is built by the data model ( .xcdatamodeld ) group that appears in your project The data model source group should be included
in the target — that group compiles all your versions and deploys a single bundle The individual .xcdatamodel source fi les inside the group should not
be included in the same target If you include both, the application ’ s bundle will contain duplicate data models — one inside the bundle and one outside.
Core Data will (by default) attempt to merge these, and your application will abort with obscure errors like “ Can ’ t merge models with two different
erase any stray deployments of the old model Chapter 16 explains target membership
Each version has an arbitrary version
identifi er string that you assign Open the
data model, ensure that no entities or
properties are selected, and choose the File ➪
Get Info command In the data model ’ s info
window, switch to the Versioning tab and
assign the model a version identifi er, as shown
in Figure 15 - 18
FIGURE 15-17
FIGURE 15-18
Trang 4Now make the needed modifi cations to the newly created data schema version The next two sections will help you confi gure the migration from the old schema to the new one
Adding Lightweight Migration Hints
If you are using Mac OS X 10.6 or later, Core Data provides a lightweight migration strategy for data models with only superfi cial changes If you are using an earlier version of Core Data, or if you make signifi cation changes to your data model, you ’ ll need to create a mapping, as described in the next section
Lightweight migration has several advantages:
You don ’ t have to create a migration mapping You might not have to version your data model
It ’ s fast Core Data can migrate from one schema to another as long as the changes are limited to:
Adding new attributes to an entity Making a required attribute optional
Making an optional attribute required and providing a default value
Renaming an entity Renaming an attribute
As long as your data schema changes are confi ned to this set of changes, you can use lightweight migration
Renaming an entity or attribute requires you to create a data model version and provide Core Data with a little extra assistance In the confi gurations inspector of the entity or attribute is a Renaming Identifi er, as shown in Figure 15 - 19
➤
➤
➤
➤
➤
➤
➤
➤
FIGURE 15-19
If you need to rename an entity or attribute, fi rst create a new version of your data model In the new version, rename the element and then set this fi eld to the element ’ s previous name This tells Core Data which entity or attribute in the old schema corresponds to the new one
Trang 5If you didn ’ t rename any entities or attributes, you can use lightweight migration without creating a new version of your data schema See the Data Migration Guide for the cases where you don ’ t need to create a data schema version
Creating a Migration Mapping
A migration mapping transitions the data from one schema to another You can initiate a migration
programmatically or let the Core Data framework perform it automatically, as needed In either
case, the migration proceeds in roughly the following phases:
1. The versions of the old and new data schemas are identifi ed and a suitable mapping is found
2. The old data store is opened and a new data store is created
3. Objects are created from the old data store
4. The mapping is used to create new objects in the new data store, and then insert copy/
convert the old attributes into new attributes
5. The relationships between old objects are replicated in the new objects
6. The new objects are written to the new data store and the old objects are discarded
The Core Data framework provides many of the basic tools needed to map one data schema to
another, and most of these can be confi gured in Xcode ’ s mapping model tool If you need a more
sophisticated translation, almost every phase of the migration can be infl uenced with custom code
To create a data model mapping, follow these steps:
1. Create a new data model version You must have at least two versions to create a mapping
2. Choose the File ➪ New File (or any equivalent) command
3. Select the Mapping Model template (in the Resource group)
4. Give the mapping document a name I tend to name my mappings after the model and the
versions it translates between, such as Accounts2to3.xcmappingmodel
a. Choose the project to which to add the mapping document
b. The location for the new document should be inside your project ’ s folder, preferably with the other data model documents
c. Choose the targets Each target must also include both of the data models in question
5. Xcode presents a dialog box similar to the one shown in Figure 15 - 20
a. In your project ’ s fi les, locate and select the old data model fi le You will need to expand your data model group, because you have more than one version
b. Click the Set Source Model button
c. Select the new data model fi le
Trang 6Xcode constructs a new mapping model document, and fi lls in the translations that look obvious to
it Your job is to supply anything that ’ s missing or needs to be customized
FIGURE 15-20
The mapping model document window, shown in Figure 15 - 22, is organized very much like the data model browser: the left column lists the entity mappings Selecting an entity mapping displays the property mappings for that entity mapping in the middle column On the right is a details pane where you set the specifi cs for the selected entity or property mapping You can add or remove mappings using the + and – buttons/menus at the bottom of the columns
Order is sometimes important Entity mappings are performed in a specifi c order, and if you have mappings that depend on previous mappings then that order may be signifi cant To change the order, fi rst sort the entity mappings column
by order (the # column) You can then drag entity rows into the sequence you desire
Most of the details concern how entities are mapped to other entities, and how the attributes of new objects are determined using the content of old objects
One fi eld of note is the Custom Policy property of an entity mapping A custom migration policy object is a subclass of NSEntityMigrationPolicy It receives a series of messages as the various migration phases are performed, allowing you to inject custom code into the process Enter the name of your custom subclass of NSEntityMigrationPolicy into the fi eld Core Data creates an instance of your class and lets it participate in various aspects of entity migration
Trang 7An example serves as a good explanation Let ’ s say you have a Core Data project that is just getting
started You begin by defi ning a User entity that has firstName , lastName , location , and email
attributes
It ’ s a good start, and you ’ ve entered some data into your database, but you quickly realize that
a separate table so you can relate multiple accounts that use the same e - mail address You continue
development, following these steps:
1. Open the current data model Make sure it ’ s saved Choose Design ➪ Data Model ➪ Add
Model Version
2. Open the new data model ( BigBrother_DataModel 2 )
3. Select the User entity mapping Rename the location attribute to country
4. Remove the email attribute from User
5. Create a new Email entity
6. Add an emailAddress attribute to the new entity
7. Return to the User entity and add a new to - one relationship, name it email , and choose
Email as the destination entity Your model should now look like the one in Figure 15 - 21
8. Save the model and choose Design ➪ Data Model ➪ Set Current Version
9. Make whatever code and nib document changes are needed to work with your new
data model
FIGURE 15-21
Trang 8At this point, you ’ ve created a new version of your data schema and application Unfortunately, the data you already entered is in the old version and can no longer be read Launching your application
at this point would simply result in Core Data errors
You construct a mapping to convert the data in the old schema into the new one:
10. Choose File ➪ New File, select the Mapping Model template, and name it BigBrother1to2.xcmappingmodel
You then edit your migration mapping to fi ll in the missing pieces:
11. Handle the attribute rename by selecting the UserToUser mapping, and then selecting the
the value of the location attribute from the old User to the country attribute in the new User
12. Select the Email entity mapping Change the source from nothing to User This now creates
a new Email entity for every User entity in the old database (There are now two mappings for the User entity, so every old User object is processed twice — once to make a new User and again to make a new Email.)
1 3. Select the emailAddress attribute mapping of the new UserToEmail mapping Enter a value expression of $source.email This copies the email attribute of the old User entity into the emailAddress attribute of the new Email entity
1 4. Select The UserToUser entity mapping, and then select the email attribute mapping Under the Auto Generate Value Expression, enter a KeyPath of $source and Mapping Name
of UserToEmail, as shown in Figure 15 - 22 This sets the email relationship in the new User object to the single object created by the UserToEmail mapping (that is, the new
Email object)
FIGURE 15-22
Trang 91 5. Add the following code to your application ’ s data store setup:
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES],
NSInferMappingModelAutomaticallyOption, nil];
16. Pass the newly created options object in the - addPersistentStoreWithType:
configuration:URL:options:error: message during startup
Your application is now ready to run When it starts, Core Data detects that your current data
model does not agree with the structure of your existing store It automatically fi nds the older
version of the data schema that does, fi nds the mapping that maps between those two models,
applies the mapping, and updates your data store
CREATING NSMANAGEDOBJECT SUBCLASSES
The beginning of this chapter mentioned that the entities you defi ne in your data model exist as
instances of NSManagedObject at run time Quite often, NSManagedObject is more than suffi cient
for your needs
You might, however, need a class with more specialized functionality for many reasons:
Localized business logic in the entity object Specialized or complex validation
Custom pre - or post - processing of attribute changes Non - standard attribute types
There are also a number of reasons why you wouldn ’ t need to subclass NSManagedObject:
Provide attribute property storage Use any of the built - in Core Data property features Inherit properties from other entities
Use Key Value Coding, Key Value Observing, or Bindings
An NSManagedObject reads a description of its entity and dynamically synthesizes real Objective - C
accessor methods at run time The result is an object that, for all intents and purposes, is identical
to a custom class that defi nes those properties in code As an example, an NSManagedObject for an
entity that defi nes a string name attribute property would be functionally identical to a custom class
that implemented accessors compatible with a @property NSString* name directive You can send
either object - name and - setName: messages, watch for changes using Key Value Observing, and so
on Ask yourself if you really need to subclass NSManagedObject before continuing
To create a custom implementation class for an entity, start by subclassing NSManagedObject You
cannot use just any arbitrary class; your class must be a subclass of NSManagedObject The easiest
way to get started is to use the Managed Object Class fi le template This template appears only
➤
➤
➤
➤
➤
➤
➤
➤