What Is Core Data?

Core Data is a framework that you use to manage the model layer objects in your application. It provides generalized and automated solutions to common tasks associated with object life cycle and object graph management, including persistence.


Core Data typically decreases by 50 to 70 percent the amount of code you write to support the model layer. This is primarily due to the following built-in features that you do not have to implement, test, or optimize:

Core Data减少百分之50到百分子70的你用来支持模型层的代码。这是因为一下的特征植入 你不用去实现测试或优化:

Change tracking and built-in management of undo and redo beyond basic text editing. 


Maintenance of change propagation, including maintaining the consistency of relationships among objects. 


Lazy loading of objects, partially materialized futures (faulting), and copy-on-write data sharing to reduce overhead. 


Automatic validation of property values. Managed objects extend the standard key-value coding validation methods to ensure that individual values lie within acceptable ranges, so that combinations of values make sense. 


Schema migration tools that simplify schema changes and allow you to perform efficient in-place schema migration. 



Optional integration with the application’s controller layer to support user interface synchronization. 


Grouping, filtering, and organizing data in memory and in the user interface. 

分组,过滤,组织数据 在内存中和在用户界面中。

Automatic support for storing objects in external data repositories. 

Sophisticated query compilation. Instead of writing SQL, you can create complex queries by associating an NSPredicate object with a fetch request. 


Version tracking and optimistic locking to support automatic multiwriter conflict resolution. 


Effective integration with the OS X and iOS tool chains. 

Creating a Managed Object Model


Much of Core Data’s functionality depends on the schema you create to describe your application’s entities, their properties, and the relationships between them. Core Data uses a schema called a managed object model — an instance of NSManagedObjectModel. In general, the richer the model, the better Core Data is able to support your application.

CD的大部分功能是基于你创建的描述你的应用的实体的图表,它们的属性,和它们之间的关系。CD使用一个被称作 管理对象模型 -一个NSManagedObjecctModel 实例的图表。总的来说,模型越丰富,CD支持你的应用越好。

A managed object model allows Core Data to map from records in a persistent store to managed objects that you use in your application. The model is a collection of entity description objects (instances of NSEntityDescription). An entity description describes an entity (which you can think of as a table in a database) in terms of its name, the name of the class used to represent the entity in your application, and what properties (attributes and relationships) it has.

一个管理对象模型允许CD去去映射(关联)在持久存储中的记录去管理你在应用中使用的对象。这个模型师一个 实体描述 对象 的集合(NSEntityDescription的实例)。一个 实体描述 描述一个实体(你能把它想象成一个在数据库中的表)依据它的名字,这个类的名字用来展示这个实体在你的应用中,和什么属性(属性和关系)它有。

Creating an Entity and Its Properties


When you start a new project in Xcode and open the template selection dialog, select the Use Core Data checkbox. A source file for the Core Data model is created as part of the template. That source file will have the extension .xcdatamodeld. Select that file in the navigator area to display the Core Data model editor.

当你开始一个项目在Xcode 和打开对话选择模版,选择使用CD复选框,一个源文件为CD 模型被创建作为模版的一部分。这个源文件将有.xcdatamodeld后缀。选择那个文件在导航区域去展示CD模型编辑。

To create an entity

1 Click Add Entity.
A new untitled entity will appear in the Entities list in the navigator area. 



2 Select the new untitled entity. 


3 In the Entity pane of the Data Model inspector, enter the name of the entity, and press Return. 


To create attributes and relationships for the entity


1 With the new entity selected, click the plus(+) sign at the bottom of the appropriate section. 

A new untitled attribute or relationship (generically referred to as properties) is added under the Attributes or Relationships section of the editor area. 


2 Select the new untitled property.
The property settings are displayed in the Relationships or Attributes pane of the Data Model inspector. 



3 Give the property a name and press Return.
The attribute or relationship information appears in the editor area. 

Figure 2-2 shows an entity called Employee, with attributes that describe the employee: date of birth, name, and start date.



Figure 2-1Employee entity in the Xcode Data Model editor


At this point you have created an entity in the model, but you have not created any data. Data is created later, when you launch your application. Inside of your application these entities will be used as the basis for the creation of managed objects (NSManagedObject instances).

到这里你已经在模型中创建一个实体,但是你还有没有创建数据。数据在以后被创建,当你启动你的APP,在你的app中插入的实体将被用来做为基础来创建管理对象(NSManaedObject   instances).

Defining an Entity

Now that you have named your entity, you will define it further in the Entity pane of the Data Model inspector.


Figure 2-2Entity pane in the Data Model inspector


Entity Name and Class Name


Note that the entity name and the class name (a subclass of NSManagedObject) are not the same. The entity structure in the data model does not need to match the class hierarchy. Figure 2-2 shows a class name with the recommended class name pattern of Objective-C, along with an MO suffix. An entity name and a class name are required.

主要实体名和类名(NSManagedObject 的子类)不是相同的。在数据模型中的实体结构不需要去复合类的层级。表2-2展示了一个使用推荐的OC命名模式的类名,有一个MO的后缀。一个实体名字和一个类名是需要的。

Abstract Entities


Specify that an entity is abstract if you will not create any instances of that entity. You typically make an entity abstract if you have a number of entities that all represent specializations of (inherit from) a common entity that should not itself be instantiated. For example, in the Employee entity you could define Person as an abstract entity and specify that only concrete subentities (Employee and Customer) can be instantiated. By marking an entity as abstract in the Entity pane of the Data Model inspector, you are informing Core Data that it will never be instantiated directly.

如果你不创建任何这个实体的实例的时候你可以把这个指定一个实体是抽象。你创建一个抽象实体 如果你有一批的实体都展示特殊化的(继承)一个共同的自己不应该被实例化的实体。比如,在雇员实体应该定义一个人做为一个抽象实体 和 明确只有 具体化的子实体 (雇员和客户) 能被实体化。通过让一个实体作为抽象实体在数据模型查看器的实体窗口中,你通知了DC这个实体用远不会被直接实体化。

Entity Inheritance

Entity inheritance works in a similar way to class inheritance, and is useful for the same reasons. If you have a number of entities that are similar, you can factor the common properties into a superentity, also known as a parent entity. Rather than specifying the same properties in several entities, you can define them in one entity, and the subentities inherit them. For example, you might define a Person entity with attributes firstName and lastName, and subentities Employee and Customer, which inherit those attributes. An example of this layout is shown in Figure 2-3. Display the layout diagram by clicking on the Editor Style toggle switch in the lower right corner.

In many cases, you also implement a custom class to correspond to the entity from which classes representing the subentities also inherit. Rather than implementing business logic common to all the entities several times over, you implement them in one place and they are inherited by the subclasses.

实体继承工作方式和类的继承是相似的,因为相同的原因很有用。如果你有一批的实体是相似的,你能把相同的属性工厂化到一个父实体中,又称作为一个父实体。比起在几个实体中明确相同的属性。你在一个实体中定义它们,和子类实体继承它们。比如你可能使用属性firstName 和lastName定义一个人,和子实体雇员和客户类继承哪些属性,一个这个的布局例子被战胜在表2-3.通过点击在右下角低处的编辑风格切换开关展示布局表。



Be careful with entity inheritance when working with SQLite persistent stores. All entities that inherit from another entity will exist within the same table in SQLite. This factor in the design of the SQLite persistent store can create a performance issue.

使用实体继承要当心在你使用SQLite持久存储的时候。所有从另一个实体继承的实体将存在于SQLite中的相同的表上。这个因素在设计SQLite 持久化存储中能造成性能问题。

Figure 2-3Entity inheritance diagram


Defining Attributes and Relationships


An entity’s properties are its attributes and relationships, including its fetched properties (if it has any). Among other features, each property has a name and a type. A property name cannot be the same as any no-parameter method name of NSObject or NSManagedObject — for example, you cannot give a property the name “description” (see NSPropertyDescription).

Transient attributes are properties that you define as part of the model, but which are not saved to the persistent store as part of an entity instance’s data. Core Data does track changes you make to transient properties, so they are recorded for undo operations. You use transient properties for a variety of purposes, including keeping calculated values and derived values.


Transient attributes;

暂时属性是你定义作为模型一部分的属性,它不会被保存到持久存储 作为实体实例数据。CD会追踪你让暂时属性发生的改变,所以它们被记录为撤销操作。你使用暂时属性达到很多的目的,包括保存计算的值和获得值。


If you undo a change to a transient property that uses nonmodeled information, Core Data does not invoke your set accessor with the old value — it simply updates the snapshot information.


Figure 2-4Attribute pane in the Data Model inspector



To define an attribute, select it in the Core Data model editor and specify values in the Attribute pane of the Core Data Model inspector. Core Data natively supports a variety of attribute types, such as string, date, and integer (represented as instances of NSString, NSDate and NSNumber respectively).

You can specify that an attribute is optional — that is, it is not required to have a value. In general, however, you are discouraged from doing so, especially for numeric values. Typically, you can get better results using a mandatory attribute with a default value — defined in the attribute — of 0. The reason for this is that SQL has special comparison behavior for NULL that is unlike Objective-C’s nil. NULL in a database is not the same as 0, and searches for 0 will not match columns with NULL. Moreover, NULL in a database is not equivalent to an empty string or empty data blob.

去定义一个属性,在CD模型编辑器中选择它和在CD模型检查器的属性窗口明确它的值。CD仅仅支持固有的几种属性类型,比如字符串,日期,整数(分别作为NSString,NSDate和NSNumber的实例展示)。你能明确一个属性是可选的-也就是,它不是必须有一个值的。通常来说,最好别这样做,特别是数字类型的值。你能 使用一个强制的有默认值- 定义在属性中的-0 的属性 获得更好的结果。这样做的原因是SQL有特别的针对NULL而不像Objective-C中的nil  的对比行为。NULL在一个数据基库中是和0不同的,搜索0将不会匹配为NULL的列。此外,NULL在一个数据基库和一个空字符串或空数据团是不同的。

Relationships and Fetched Properties


To define a relationship, select it in the Core Data model editor, and specify values in the Relationship pane of the Data Model inspector.


Figure 2-5Relationship in the Data Model inspector


Core Data supports to-one and to-many relationships, and fetched properties. Fetched properties represent weak, one-way relationships. In the employees and departments domain, a fetched property of a department might be “recent hires” (employees do not have an inverse to the recent hires relationship).

CD支持到 一个 和 到多个 关系,和读取属性。获取属性展示弱的,单-路关系,在雇员和部门作用范围。一个部分的一个获取属性可能被“暂时雇佣”(雇员没有一个到暂时关系 的反向)。

The Type field defines whether the relationship is a to-one type relationship or a to-many type relationship. Relationships are defined from one direction at a time. To create a many-to-many relationship, you would need to create two to-many relationships and then set them up as inverses of each other.

The Destination field defines what object (or objects) are returned when the relationship is accessed in code. If the relationship is defined as to-one then a single object (or nil if the relationship can be optional) will be returned. If the relationship is defined as to-many, then a set will be returned (or again, nil if the relationship can be optional).

Type 类型区域定义是否 关系是一个 对一类型或是一个对多类型关系。关系在同一时间只能定义一个方向。去创建一个 多对多关系,你将需要创建 两对多 关系然后设置它们彼此之间的可逆。

Destination 区域定义什么对象(或对象们)被返回当关系被访问在代码中。如果关系被定义为 对一 然后一个单独的对象(或nil如果关系是可选的)将被返回。如果关系被定义为 对多,然后一个集合被返回(或再一次,nil 如果关系是可选的)。

The Inverse field defines the other half of a relationship. Because each relationship is defined from one direction, this field joins two relationships together to create a fully bidirectional relationship.

Inverse 区域定义一个关系的另一半。因为每个关系被从一个方向定义,这个区域结合两个关系到一起去创建一个充分的双向关系。

Relationships are described in greater detail in Creating Managed Object Relationships.

Initializing the Core Data Stack


The Core Data stack is a collection of framework objects that are accessed as part of the initialization of Core Data and that mediate between the objects in your application and external data stores. The Core Data stack handles all of the interactions with the external data stores so that your application can focus on its business logic. The stack consists of three primary objects: the managed object context (NSManagedObjectContext), the persistent store coordinator (NSPersistentStoreCoordinator), and the managed object model (NSManagedObjectModel), discussed later in this chapter.

CD栈是一个框架对象的集合 作为CD的实例化的一部分被访问和在你的应用和扩展数据存储之间调解。CD栈处理所有和外部数据存储的交互以至于你能专注在它的业务逻辑上。这个栈持续持有三个重要的对象。管理对象上下文(NSManagedObjectContext),持久存储协调器(NSPersistentStoreCoordinator),和管理对象模型(NSManagedObjectModel),在这个章节的以后讨论。

You initialize the Core Data stack prior to accessing your application data. The initialization of the stack prepares Core Data for data requests and the creation of data. Here’s an example of how to create that Core Data stack.


Listing 3-1Example Core Data stack creation


@interface MyDataController : NSObject


@property (strong) NSManagedObjectContext *managedObjectContext;


- (void)initializeCoreData;




@implementation MyDataController


- (id)init


    self = [super init];

    if (!self) return nil;


    [self initializeCoreData];


    return self;



- (void)initializeCoreData


    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"DataModel" withExtension:@"momd"];

    NSManagedObjectModel *mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];

    NSAssert(mom != nil, @"Error initializing Managed Object Model");


    NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];

    NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];

    [moc setPersistentStoreCoordinator:psc];

    [self setManagedObjectContext:moc];


    NSFileManager *fileManager = [NSFileManager defaultManager];

    NSURL *documentsURL = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];

    NSURL *storeURL = [documentsURL URLByAppendingPathComponent:@"DataModel.sqlite"];


    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {

        NSError *error = nil;

        NSPersistentStoreCoordinator *psc = [[self managedObjectContext] persistentStoreCoordinator];

        NSPersistentStore *store = [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error];

        NSAssert(store != nil, @"Error initializing PSC: %@\n%@", [error localizedDescription], [error userInfo]);




import UIKit

import CoreData

class DataController a href="" NSObject /a  {

    var managedObjectContext a href="" NSManagedObjectContext /a 

    init() {

        // This resource is the same name as your xcdatamodeld contained in your project.

        guard let modelURL = NSBundle.mainBundle().URLForResource("DataModel", withExtension:"momd") else {

            fatalError("Error loading model from bundle")


        // The managed object model for the application. It is a fatal error for the application not to be able to find and load its model.

        guard let mom = NSManagedObjectModel(contentsOfURL: modelURL) else {

            fatalError("Error initializing mom from: \(modelURL)")


        let psc = NSPersistentStoreCoordinator(managedObjectModel: mom)

        managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)

        managedObjectContext.persistentStoreCoordinator = psc

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {

            let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)

            let docURL = urls[urls.endIndex-1]

            /* The directory the application uses to store the Core Data store file.

            This code uses a file named "DataModel.sqlite" in the application's documents directory.


            let storeURL = docURL.URLByAppendingPathComponent("DataModel.sqlite")

            do {

                try psc.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: nil)

            } catch {

                fatalError("Error migrating store: \(error)")





This example creates a controller object that represents the persistence layer of the application. The controller is initialized with a default init call. As part of that init call, the initializeCoreData method is called, and it then proceeds to create the Core Data stack.



The NSManagedObjectModel instance describes the data that is going to be accessed by the Core Data stack. During the creation of the Core Data stack, the NSManagedObjectModel (often referred to as the “mom”) is loaded into memory as the first step in the creation of the stack. The example code above resolves an NSURL from the main application bundle using a known filename (in this example DataModel.momd) for the NSManagedObjectModel. Once the NSManagedObjectModel object is initialized, the NSPersistentStoreCoordinator object is constructed.

***NSManagedObjectModel实例描述了将要被CD栈访问的数据。 ***在CD栈的创建期间,这个NSManagedObjectModel(通常叫做“mom”)被加载到内存中作为栈的创建的第一步。上面的示例代码从主应用bundle中使用一个文件名(在这个例子中是DataModel.momd)得到一个NSURL 为 NSManagedObjectModel.一旦这个NSManagedObjectModel对象被初始化,这个NSPersistentStoreCoordinator对象被构造。


The NSPersistentStoreCoordinator sits in the middle of the Core Data stack. The coordinator is responsible for realizing instances of entities that are defined inside of the model. It creates new instances of the entities in the model, and it retrieves existing instances from a persistent store (NSPersistentStore). The persistent store can be on disk or in memory. Depending on the structure of the application, it is possible, although uncommon, to have more than one persistent store being coordinated by the NSPersistentStoreCoordinator.

Whereas the NSManagedObjectModel defines the structure of the data, the NSPersistentStoreCoordinator realizes objects from the data in the persistent store and passes those objects off to the requesting NSManagedObjectContext. The NSPersistentStoreCoordinator also verifies that the data is in a consistent state that matches the definitions in the NSManagedObjectModel.



***NSPersistentStoreCoordinator 从在持久存储数据中实例对象和传输哪些对象到请求 NSManagedObjectContext***.这个NSPersistentStoreCoordinator 也验证在持久状态的匹配在NSManagedObjectModel定义的数据。


The managed object context (NSManagedObjectContext) is the object that your application will be interacting with the most, and therefore it is the one that is exposed to the rest of your application. Think of the managed object context as an intelligent scratch pad. When you fetch objects from a persistent store, you bring temporary copies onto the scratch pad where they form an object graph (or a collection of object graphs). You can then modify those objects however you like. Unless you actually save those changes, however, the persistent store remains unaltered.


All managed objects must be registered with a managed object context. You use the context to add objects to the object graph and remove objects from the object graph. The context tracks the changes you make, both to individual objects’ attributes and to the relationships between objects. By tracking changes, the context is able to provide undo and redo support for you. It also ensures that if you change relationships between objects, the integrity of the object graph is maintained.

所有管理对象必须使用一个管理对象上下文注册。你使用上下文去添加对象到对象图表和从对象图表中移除对象。这个上下文追逐你做的改变,不管上单个 对象的属性和对象之间的关系。通过追踪改变,上下文能够提供给你重复和撤销的操作。它也确保如果你改变对象之间的关系,对象图表的完整形被保持。

If you choose to save the changes you have made, the context ensures that your objects are in a valid state. If they are, the changes are written to the persistent store (or stores), new records are added for objects you created, and records are removed for objects you deleted.


Without Core Data, you have to write methods to support archiving and unarchiving of data, to keep track of model objects, and to interact with an undo manager to support undo. In the Core Data framework, most of this functionality is provided for you automatically, primarily through the managed object context.



Creating and Saving Managed Objects

Once you have defined your managed object model and initialized the Core Data stack within your application, you are ready to start creating objects for data storage.


Creating Managed Objects


An NSManagedObject instance implements the basic behavior required of a Core Data model object. The NSManagedObject instance requires two elements: an entity description (an NSEntityDescription instance) and a managed object context (an NSManagedObjectContext instance). The entity description includes the name of the entity that the object represents and its attributes and relationships. The managed object context represents a scratch pad where you create the managed objects. The context tracks changes to and relationships between objects.




2.一个管理对象上下文(一个NSManagedObjectContext 实例)。



As shown in this example, the NSEntityDescription class has a class method that accepts a string for the name of the entity and a reference to the NSManagedObjectContext that the NSManagedObject instance will be associated with. The example defines the returning object as AAAEmployeeMO object.

像这个例子中显示的一样,这个NSEntityDescription 类有一个类方法它接收一个字符串作为实体的名字和引用到NSManagedObject 实例将协助的NSManagedObjectContext。这个例子定义了返回对象作为一个AAAEmplayeeMo对象。


AAAEmployeeMO employee = [NSEntityDescription insertNewObjectForEntityForName:@"Employee" inManagedObjectContext:[self managedObjectContext];


let employee = NSEntityDescription.insertNewObjectForEntityForName("Employee", inManagedObjectContext: self.managedObjectContext) as a href="" AAAEmployeeMO /a 

Creating NSManagedObject Subclasses

By default, Core Data will return NSManagedObject instances to your application. However, it is useful to define subclasses of NSManagedObject for each of the entities in your model. Speciflcally, when you create subclasses of NSManagedObject, you can define the properties that the entity can use for code completion and you can add convenience methods to those subclasses.

To create a subclass of NSManagedObject, in Xcode’s Core Data model editor, select the entity, and in the Entity pane of the Data Model inspector, enter the name in the Class field. Then create the subclass (AAAEmployeeMO) in Xcode.

默认情况。CD将返回NSManagedObject对象到你的应用。然而,定义NSManagedObject的之类为每一个在你的模型中的实体很有用。特别是,当你创建NSManagedObject的子类,你能定义实体能用代码完成属性和你能添加便利方法到它的子类。去创建NSManagedObject的子类,在Xcode的CD模型编辑器,选择实体,和在数据模型查看器的实体窗口,输入名字在 Class 区域。然后创建子类在Xcode中。


#import <CoreData/CoreData.h>


@interface AAAEmployeeMO : NSManagedObject


@property (nonatomic, strong) NSString *name;




@implementation AAAEmployeeMO


@dynamic name;




import UIKit

import CoreData

import Foundation


class AAAEmployeeMO a href="" NSManagedObject /a  {


    @NSManaged var name a href="" String /a ?



The @dynamic tag informs the compiler that the variable will be resolved at runtime.


Once the subclass has been defined in your data model and added to your project, you can reference it directly in your application and improve the readability of your application code.


Saving NSManagedObject Instances

保持NSManagedObject 实例

The creation of NSManagedObject instances does not guarantee their persistence. Once you create an NSManagedObject instance in your managed object context, you must explicitly save that context to persist those changes to your persistent store.



NSError *error = nil;

if ([[self managedObjectContext] save:&error] == NO) {

    NSAssert(NO, @"Error saving context: %@\n%@", [error localizedDescription], [error userInfo]);



do {


} catch {

    fatalError("Failure to save context: \(error)")


The call to save on the NSManagedObjectContext accepts a reference to an NSError variable and always returns either a success or a fail. If the save fails, it is important to display the error condition so that it can be corrected. The display of that error condition can be as simple as outputting the error to the console or as complicated as offering the error message to the user. If the save method returns a success, then the error variable does not need to be consulted.


Creating and Modifying Custom Managed Objects

As discussed previously, managed objects are instances of the NSManagedObject class, or of a subclass of NSManagedObject, that represent instances of an entity. NSManagedObject is a generic class that implements all the basic behavior required of a managed object. You can create custom subclasses of NSManagedObject, although this is often not required. If you do not need any custom logic for a given entity, you do not need to create a custom class for that entity. You implement a custom class to, for example, provide custom accessor or validation methods, use nonstandard attributes, specify dependent keys, calculate derived values, and implement any other custom logic.

正如上面讨论的,管理对象是展示一个实体的例子 ,是NSManagedObject类的实例,或 NSManagedObject 子类的。NSManagedObject是一个普通实现一个管理对象的所有基本需要行为的类。你能创建自定义的NSManagedObject的子类,尽管这个通常不需要。如果你不需要任何自定义逻辑为一个给定实体,你不需要为那个实体创建一个自定义的类。你实现一个自定义类去,比如提供自定义的访问或验证方法,使用非标准的属性,明确独立keys,计算衍生值,和实现你任何其它自定逻辑。

Creating Custom Managed Object Subclasses


In an Objective-C managed object subclass, you can declare the properties for modeled attributes in the interface file, but you don’t declare instance variables:


@interface MyManagedObject : NSManagedObject


@property (nonatomic, strong) NSString *title;

@property (nonatomic, strong) NSDate *date;



Notice that the properties are declared as nonatomic and strong. For performance reasons, Core Data typically does not copy object values, even if the value class adopts the NSCopying protocol.

注意属性被声明为nonatomic 和strong.因为性能原因,CD不会拷贝对象值,就算值类采用了NSCopying 协议。

In the Objective-C implementation file, you specify the properties as dynamic:


@implementation MyManagedObject

@dynamic title;

@dynamic date;


In Swift, you declare the properties using the @NSManaged keyword:

class MyManagedObject a href="" NSManagedObject /a  {

    @NSManaged var title a href="" String /a ?

    @NSManaged var date a href="" NSDate /a ?


Core Data dynamically generates efficient public and primitive get and set attribute accessor methods and relationship accessor methods for properties that are defined in the entity of a managed object’s corresponding managed object model. Therefore, you typically don’t need to write custom accessor methods for modeled properties.

CD动态生成高效公共的和原始获取和设置属性访问方法和关系访问方法 为 定义在一个管理对象的相关的管理对象模型 实体中的属性。***因此你不需要为模型化的属性写自定义的访问方法。

Guidelines for Overriding Methods

NSManagedObject itself customizes many features of NSObject so that managed objects can be properly integrated into the Core Data infrastructure. Core Data relies on NSManagedObject’s implementation of the following methods, which you should therefore not override:






















You are discouraged from overriding initWithEntity:insertIntoManagedObjectContext: and description. If description fires a fault during a debugging operation, the results may be unpredictable. You should typically not override the key-value coding methods such as valueForKey: and setValue:forKeyPath:.

In addition, before overriding awakeFromInsert, awakeFromFetch, and validation methods such as validateForUpdate:, invoke their superclass implementation. Be careful when overriding accessor methods because you could negatively impact performance.

不能从写initWithEntity:insertIntoManagedObjectContext:和description.如果description产生一个错误在调试操作中,结果是不可预知的。尤其不能重写key-value编码方法,比如valueForKey:和 setValue:forKeyPath:


Defining Properties and Data Storage


In some respects, a managed object acts like a dictionary—it is a generic container object that efficiently provides storage for the properties defined by its associated NSEntityDescription object. NSManagedObject supports a range of common types for attribute values, including string, date, and number (see NSAttributeDescription for full details). Therefore, you typically do not need to define instance variables in subclasses. However, if you need to implement nonstandard attributes or preserve timezones, you may need to do so. In addition, there are some performance considerations that can be mitigated in a subclass if you use large binary data objects—see Binary Large Data Objects (BLOBs).

在一些方面,一个关系对象表现的像一个字典-它是一个通用容器对象 高效提供存储为被相关NSEntityDescription对象定义的属性。NSManagedObject 支持一系列的通用类型 为属性值,包括字符串,日期,和数字(参见NSAttributeDescription得到所有细节)。因此,你不需要去定义示例变量在子类中。然而如果你需要去实现非标准属性或保存时区,你可能需要这样做。另外,有一些执行考虑 如果你使用大的二进制数据对象 就会减轻执行压力。

Using Nonstandard Attributes


By default, NSManagedObject stores its properties as objects in an internal structure, and in general Core Data is more efficient working with storage under its own control than with using custom instance variables.

Sometimes you need to use types that are not supported directly, such as colors and C structures. For example, in a graphics application you might want to define a Rectangle entity that has attributes color and bounds, which are instances of NSColor and an NSRect structures respectively. This situation requires you to create a subclass of NSManagedObject.

通过默认,NSManagedObject 存储它的属性作为在内在结构中的对象,通常来说CDCD使用在它自己控制的存储会更高效相比于使用自定义的实力变量。有时你需要去使用不是直接支持的类型,比如颜色或C  结构体。比如在一个图表应用中你可能想去定义一个有属性为颜色和边界的矩形实体,它们各自是NSColor的实例 和一个NSRect结构体。这个情况要求i去创建一个NSManagedObject子类。

Dates, Times, and Preserving Timezones


NSManagedObject represents date attributes with NSDate objects, and stores times internally as an NSTimeInterval value which is based on GMT. Time zones are not explicitly stored — indeed you should always represent a Core Data date attribute in GMT, so that searches are normalized in the database. If you need to preserve the time zone information, you need to store a time zone attribute in your model, which may require you to create a subclass of NSManagedObject.


Customizing Initialization and Deallocation


Core Data controls the life cycle of managed objects. With faulting and undo, you cannot make the same assumptions about the life cycle of a managed object that you do with a standard Objective-C object — managed objects can be instantiated, destroyed, and resurrected by the framework as it requires.

CD控制管理对象的生命周期。有故障和撤销,你不能设置相同的关于你在标准Objective-C对象管理对象生命周期假设-管理对象能被创建,销毁,和通过框架复苏 如果它需要。

When a managed object is created, it is initialized with the default values given for its entity in the managed object model. In many cases the default values set in the model are sufficient. Sometimes, however, you may wish to perform additional initialization—perhaps using dynamic values (such as the current date and time) that cannot be represented in the model.

当一个管理对象被创建,它被创建 使用默认值 给它的在管理对象模型实体。在很多场合默认值设置在模型中是充足的。有时,然后你可能希望去执行额外的初始化-可能使用动态值(比如当前日期和时间)不能够被在模型中体现。

In a typical Objective-C class, you usually override the designated initializer (often the init method). In a subclass of NSManagedObject, there are three different ways you can customize initialization — by overriding initWithEntity:insertIntoManagedObjectContext:, awakeFromInsert, or awakeFromFetch. Do not override init. You are discouraged from overriding initWithEntity:insertIntoManagedObjectContext:, because state changes made in this method may not be properly integrated with undo and redo. The two other methods, awakeFromInsert and awakeFromFetch, allow you to differentiate between two different situations:


awakeFromInsert is invoked only once in the lifetime of an object—when it is first created. 


awakeFromInsert is invoked immediately after you invoke initWithEntity:insertIntoManagedObjectContext: or insertNewObjectForEntityForName:inManagedObjectContext:. You can use awakeFromInsert to initialize special default property values, such as the creation date of an object, as illustrated in the following example. 



- (void)awakeFromInsert


    [super awakeFromInsert];

    [self setCreationDate:[NSDate date]];



override func awakeFromInsert() {


    creationDate = NSDate()


awakeFromFetch is invoked when an object is reinitialized from a persistent store (during a fetch). 

awakeFromFetch 被唤醒当对象被再次初始化从一个持久存储中(在获取期间)。
You can override
awakeFromFetch to, for example, establish transient values and other caches. Change processing is explicitly disabled in awakeFromFetch so that you can conveniently use public set accessor methods without dirtying the object or its context. This disabling of change processing does mean, however, that you should not manipulate relationships, as changes will not be properly propagated to the destination object or objects. Instead of overriding awakeFromFetch, you can override awakeFromInsert or employ any of the run loop-related methods such as performSelector:withObject:afterDelay:

你能重写awakeFromFetch,比如,建立瞬时值和其它高速缓存。改变处理是明确禁用的 在awakeFromFetch 所以你能方便使用公共设置方法而不用污染对象或它的上下文。这个改变线程的不可用不意味着,然而。你不应该操作关系,因为改变将被适当的传播到目的对象。而不是重写awakeFromFetch,你能重写awakeFromInsert或使用任何与运行循环相关的方法比如performSelector:withObject:afterDelay:

Avoid overriding dealloc to clear transient properties and other variables. Instead, override didTurnIntoFault. didTurnIntoFault is invoked automatically by Core Data when an object is turned into a fault and immediately prior to actual deallocation. You might turn a managed object into a fault specifically to reduce memory overhead (see Reducing Memory Overhead), so it is important to ensure that you properly perform cleanup operations in didTurnIntoFault.


***而是重写didTurnIntoFault.didTurnIntoFault 被CD自动唤醒当对象被转入到错误和立即在实际中释放。你可能转化一个管理对象到一个错误 特别是去减少内存过多(参见Reducing Memory Overhead),所以去保证你属性执行清除操作在didTurnIntoFault是重要的***。

Fetching Objects


Now that data is stored in the Core Data persistent store, you will use an NSFetchRequest to access that existing data. The fetching of objects from Core Data is one of the most powerful features of this framework.


Fetching NSManagedObject Instances


In this example you start by constructing an NSFetchRequest that describes the data you want returned. This example does not add any requirements to that data other than the type of entity being returned. You then call executeFetchRequest:error: on the NSManagedObjectContext and pass in the request along with a pointer to an error.



NSManagedObjectContext *moc = …;

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];


NSError *error = nil;

NSArray *results = [moc executeFetchRequest:request error:&error];

if (!results) {

    DLog(@"Error fetching Employee objects: %@\n%@", [error localizedDescription], [error userInfo]);




let moc = managedObjectContext

let employeesFetch = NSFetchRequest(entityName: "Employee")


do {

    let fetchedEmployees = try moc.executeFetchRequest(employeesFetch) as! [ a href="" AAAEmployeeMO /a ]

} catch {

    fatalError("Failed to fetch employees: \(error)")


The executeFetchRequest:error: method has two possible results. It will either return an NSArray object with zero or more objects, or it will return nil. If nil is returned, you have received an error from Core Data and need to respond to it. If the array exists, you receive possible results for the request even though the NSArray may be empty. An empty NSArray indicates that there were no records found.


Filtering Results


The real flexibility in fetching objects comes in the complexity of the fetch request. To begin with, you can add an NSPredicate object to the fetch request to narrow the number of objects being returned. For example, if you only want Employee objects that have a firstName of Trevor, you add the predicate directly to NSFetchRequest:



NSString *firstName = @"Trevor";

[fetchRequest setPredicate:[NSPredicate predicateWithFormat:@"firstName == %@", firstName]];


let firstName = "Trevor"

fetchRequest.predicate = NSPredicate(format: "firstName == %@", firstName)

In addition to narrowing the objects being returned, you can configure how those objects are returned. For example, you can instruct Core Data to return NSDictionary instances instead of fully formed NSManagedObject instances. Further, you can configure the NSFetchRequest so that those NSDictionary instances only contain a subset of the properties available on the Employee entity.

除了去限制被返回的对象,你能配置哪些对象被如何返回。比如你能知道CD去返回NSDictionary 实例而不是完全形成NSManagedObject实例。

***更深,你能配置NSFetchRequest 所以哪些NSDictionary实例仅仅包含在雇员实体中一个属性变量的子集合***。

For more information about NSFetchRequest, see the class documentation.


Connecting the Model to Views


In OS X, Core Data is designed to work with the user interface through Cocoa bindings. However, Cocoa bindings are not a part of the user interface in iOS. In iOS, you use NSFetchedResultsController to connect the model (Core Data) to the views (storyboards).

在OS X,CD被设计通过Cocoa连接使用用户界面去工作。然而,Cocoa连接在iOS中不是用户界面的一部分。在iOS中你使用NSFetchedResultsController去连接模型(Core Data)到Views(故事板上)。

NSFetchedResultsController provides the interface between Core Data and UITableView objects. Because table views are the most common way to display data in iOS, UITableView handles nearly all high-volume data displays. 

NSFetchedResultsController 提供在CD和UITableView对象之间的界面。因为table view是最常见的在iOS中展示数据的方式,UITableView处理几乎所有高-容量数据展示。

Creating a Fetched Results Controller


Typically, an NSFetchedResultsController instance will be initialized by an UITableViewController instance that is going to utilize it. This initialization can take place in the  viewDidLoad  or  viewWillAppear  methods, or at another logical point in the life cycle of the view controller. This example shows the initialization of the NSFetchedResultsController.

通常,一个NSFetchedResultsController实例将被一个将要使用它UITableViewController实例初始化。这个初始化能发生在ViewDidLoad或viewWillAppear 方法中,或在VC生命循环的 另外逻辑点。这个例子展示NSFetchedResultsController的初始化。


@property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;


- (void)initializeFetchedResultsController


    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];


    NSSortDescriptor *lastNameSort = [NSSortDescriptor sortDescriptorWithKey:@"lastName" ascending:YES];


    [request setSortDescriptors:@[lastNameSort]];


    NSManagedObjectContext *moc = …; //Retrieve the main queue NSManagedObjectContext


    [self setFetchedResultsController:[[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:moc sectionNameKeyPath:nil cacheName:nil]];

    [[self fetchedResultsController] setDelegate:self];


    NSError *error = nil;

    if (![[self fetchedResultsController] performFetch:&error]) {

        NSLog(@"Failed to initialize FetchedResultsController: %@\n%@", [error localizedDescription], [error userInfo]);





var fetchedResultsController a href="" NSFetchedResultsController /a !


func initializeFetchedResultsController() {

    let request = NSFetchRequest(entityName: "Person")

    let departmentSort = NSSortDescriptor(key: "", ascending: true)

    let lastNameSort = NSSortDescriptor(key: "lastName", ascending: true)

    request.sortDescriptors = [departmentSort, lastNameSort]


    let moc = self.dataController.managedObjectContext

    fetchedResultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: moc, sectionNameKeyPath: "", cacheName: "rootCache")

    fetchedResultsController.delegate = self


    do {

        try fetchedResultsController.performFetch()

    } catch {

        fatalError("Failed to initialize FetchedResultsController: \(error)")



In the initializeFetchedResultsController method shown above that will live within the controlling UITableViewController instance, you first construct a fetch request (NSFetchRequest), which is at the heart of the NSFetchedResultsController. Note that the fetch request contains a sort descriptor (NSSortDescriptor). NSFetchedResultsController requires at least one sort descriptor to control the order of the data that is being presented.


Once the fetch request is initialized, you can initialize the NSFetchedResultsController instance. The fetched results controller requires you to pass it an NSFetchRequest instance and a reference to the managed object context (NSManagedObjectContext) that the fetch is to be run against. The sectionNameKeyPath and the cacheName properties are both optional.

一旦获取请求被初始化,你能初始化NSFetchedResultsController 实例。这个获取请求控制器需要你去传给它一个NSFetchRequest实例和相关的获取被运行的管理对象上下文(NSManagedObjectContext)。这个sectionNameKeyPath 和cacheName属性都是可选的。

Once the fetched results controller is initialized, you assign it a delegate. The delegate will notify the table view controller when any changes have occurred to the underlying data structure. Typically, the table view controller will also be the delegate to the fetched results controller so that it can receive callbacks whenever there are changes to the underlying data.

一旦获取结果控制器被初始化,你指定它一个代理。这个代理将通知table view 控制器 当任何改变已经发生在底层的数据结构中。通常,table view 控制器将成为获取结果控制器的代理所以它能接受任何时候底层数据发生改变的回调

Next, you start the NSFetchedResultsController by a call to performFetch:. This call retrieves the initial data to be displayed and causes the NSFetchedResultsController instance to start monitoring the managed object context for changes.


Integrating the Fetched Results Controller with the Table View Data Source

整合获取结果控制器和Table View 数据源

After you integrate the initialized fetched results controller and have data ready to be displayed in the table view, you need to integrate the fetched results controller with the table view data source (UITableViewDataSource).

在你整合这个被初始化的获取结果控制器和有了准备被展示在table view 中的数据以后,你需要去整合获取结果控制器和table view 数据源(UITableViewDataSource).


#pragma mark - UITableViewDataSource


- (void)configureCell:(id)cell atIndexPath:(NSIndexPath*)indexPath


    id object = [[self fetchedResultsController] objectAtIndexPath:indexPath];


    // Populate cell from the NSManagedObject instance




- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath


    id cell = [tableView dequeueReusableCellWithIdentifier:CellReuseIdentifier];

    // Set up the cell

    [self configureCell:cell atIndexPath:indexPath];

    return cell;



- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView


    return [[[self fetchedResultsController] sections] count];



- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section


    id< NSFetchedResultsSectionInfo> sectionInfo = [[self fetchedResultsController] sections][section];

    return [sectionInfo numberOfObjects];



func configureCell(cell a href="" UITableViewCell /a , indexPath a href="" NSIndexPath /a ) {

    let employee = fetchedResultsController.objectAtIndexPath(indexPath) as a href="" AAAEmployeeMO /a 

    // Populate cell from the NSManagedObject instance

    print("Object for configuration: \(object)")



override func tableView(tableView a href="" UITableView /a , cellForRowAtIndexPath indexPath a href="" NSIndexPath /a ) ->  a href="" UITableViewCell /a  {

    let cell = tableView.dequeueReusableCellWithIdentifier("cellIdentifier", forIndexPath: indexPath) as a href="" UITableViewCell /a 

    // Set up the cell

    configureCell(cell, indexPath: indexPath)

    return cell



override func numberOfSectionsInTableView(tableView a href="" UITableView /a ) ->  a href="" Int /a  {

    return fetchedResultsController.sections!.count



override func tableView(tableView a href="" UITableView /a , numberOfRowsInSection section a href="" Int /a ) ->  a href="" Int /a  {

    let sections = fetchedResultsController.sections as! [ a href="" NSFetchedResultsSectionInfo /a ]

    let sectionInfo = sections[section]

    return sectionInfo.numberOfObjects


As shown in each UITableViewDataSource method above, the integration with the fetched results controller is reduced to a single method call that is specifically designed to integrate with the table view data source.

正如上面在每个UITableViewDataSource方法,使用获取结果控制器整合被减少到一个单独的被名曲设计去使用table view 数据源的 整合方法调用

Communicating Data Changes to the Table View


In addition to making it significantly easier to integrate Core Data with the table view data source, NSFetchedResultsController handles the communication with the UITableViewController instance when data changes. To enable this, implement the NSFetchedResultsControllerDelegate protocol:

除了让使用table view 数据源整合CD明显简单,NSFetchedResultsController处理当数据改变时和UITableViewController 交流,让这个可用,实现NSFetchedResultsControllerDelegate 协议:


#pragma mark - NSFetchedResultsControllerDelegate

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller


    [[self tableView] beginUpdates];


- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type


    switch(type) {

        case NSFetchedResultsChangeInsert:

            [[self tableView] insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];


        case NSFetchedResultsChangeDelete:

            [[self tableView] deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];


        case NSFetchedResultsChangeMove:

        case NSFetchedResultsChangeUpdate:




- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath


    switch(type) {

        case NSFetchedResultsChangeInsert:

            [[self tableView] insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];


        case NSFetchedResultsChangeDelete:

            [[self tableView] deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];


        case NSFetchedResultsChangeUpdate:

            [self configureCell:[[self tableView] cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];


        case NSFetchedResultsChangeMove:

            [[self tableView] deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];

            [[self tableView] insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];




- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller


    [[self tableView] endUpdates];



func controllerWillChangeContent(controller a href="" NSFetchedResultsController /a ) {




func controller(controller a href="" NSFetchedResultsController /a , didChangeSection sectionInfo a href="" NSFetchedResultsSectionInfo /a , atIndex sectionIndex a href="" Int /a , forChangeType type a href="" NSFetchedResultsChangeType /a ) {

    switch type {

    case .Insert:

        tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)

    case .Delete:

        tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: .Fade)

    case .Move:


    case .Update:





func controller(controller a href="" NSFetchedResultsController /a , didChangeObject anObject a href="" NSManagedObject /a , atIndexPath indexPath a href="" NSIndexPath /a ?, forChangeType type a href="" NSFetchedResultsChangeType /a , newIndexPath a href="" NSIndexPath /a ?) {

    switch type {

    case .Insert:

        tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade)

    case .Delete:

        tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)

    case .Update:

        configureCell(self.tableView.cellForRowAtIndexPath(indexPath!)!, indexPath: indexPath!)

    case .Move:

        tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)

        tableView.insertRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)




func controllerDidChangeContent(controller a href="" NSFetchedResultsController /a ) {



Implementing the four protocol methods shown above provides automatic updates to the associated UITableView whenever the underlying data changes.

实现上方展示的四个协议方法自动更新与它相关的UITableView 无论何时底层数据改变。

Adding Sections


So far you have been working with a table view that has only one section, which represents all of the data that needs to be displayed in the table view. If you are working with a large number of Employee objects, it can be advantageous to divide the table view into multiple sections. Grouping the employees by department makes the list of employees more manageable. Without Core Data, a table view with multiple sections would involve an array of arrays, or perhaps an even more complicated data structure. With Core Data, you make a simple change to the construction of the fetched results controller.

现在你已经使用只有 一个组的 table view和table view 组合在一起工作,这组展示所有的需要被展示到table view上的数据。如果你使用很多的雇员对象工作。把table view 分到很多组会更加的有利。通过部门把雇员分组使雇员清单更好管理。 没有CD,一个使用很多组的table view  将包含数组的数组,又或者一个更加复杂的数据结构。使用CD,你做一个简单的改变到获取结果控制器的结构。


- (void)initializeFetchedResultsController


    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];

    NSSortDescriptor *departmentSort = [NSSortDescriptor sortDescriptorWithKey:@"" ascending:YES];

    NSSortDescriptor *lastNameSort = [NSSortDescriptor sortDescriptorWithKey:@"lastName" ascending:YES];

    [request setSortDescriptors:@[departmentSort, lastNameSort]];

    NSManagedObjectContext *moc = [[self dataController] managedObjectContext];

    [self setFetchedResultsController:[[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:moc sectionNameKeyPath:@"" cacheName:nil]];

    [[self fetchedResultsController] setDelegate:self];


func initializeFetchedResultsController() {

    let request = NSFetchRequest(entityName: "Person")

    let departmentSort = NSSortDescriptor(key: "", ascending: true)

    let lastNameSort = NSSortDescriptor(key: "lastName", ascending: true)

    request.sortDescriptors = [departmentSort, lastNameSort]

    let moc = dataController.managedObjectContext

    fetchedResultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: moc, sectionNameKeyPath: "", cacheName: nil)

    fetchedResultsController.delegate = self

    do {

        try fetchedResultsController.performFetch()

    } catch {

        fatalError("Failed to initialize FetchedResultsController: \(error)")



In this example you add one more NSSortDescriptor instances to the NSFetchRequest instance. You set the same key from that new sort descriptor as the sectionNameKeyPath on the initialization of the NSFetchedResultsController. The fetched results controller uses this initial sort controller to break apart the data into the sections and therefore requires that the keys match.

在这个例子中你添加一个更多NSSortDescriptor实例到NSFetchRequest实例。你设置相同的和新集合描述相同的key在sectionNameKeyPath 在NSFetchedResultsController的时候。这个获取结果控制器使用这个初始化集合控制器去去吧数据区分到组中所以需要key到匹配。

This change causes the fetched results controller to break the returning Person instances into multiple sections based on the name of the department that each Person instance is associated with. The only conditions of using this feature are:

这个改变造成获取结果控制器去把返回Person 实例基于Person 实例相关的部分的名字分开到很多组中。使用这个特征的唯一状况是:

The sectionNameKeyPath property must also be an NSSortDescriptor instance. 


The NSSortDescriptor must be the first descriptor in the array passed to the fetch request.


Adding Caching for Performance


In many situations, a table view will represent a relatively static type of data. A fetch request is defined at the creation of the table view controller, and it never changes throughout the life of the application. In those situations it can be advantageous to add a cache to the NSFetchedResultsController instance so that when the application is launched again and the data has not changed, the table view will initialize instantaneously. A cache is especially useful for displaying unusually large data sets.

在很多情景中,一个table view  将展示一个相关的静态类型数据。一个获取请求被定义在tableViewController的创建,和永不改变在应用的生命中。在哪些场景中去添加一个高速缓存到NSFetchedResultsController实例是有利的所以当应用再一次启动数据还没有改变,这个table view将立即初始化。一个高速缓存在展示非常见的大数据集合非常有用。


[self setFetchedResultsController:[[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:moc sectionNameKeyPath:@"" cacheName:@"rootCache"]];


fetchedResultsController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: moc, sectionNameKeyPath: "", cacheName: "rootCache")

As shown above, the cacheName property is set when the NSFetchedResultsController instance is initialized, and the fetched results controller automatically gains a cache. Subsequent loading of the data will be nearly instantaneous.

像上方展示的,这个cacheName属性是一个集合 当NSFetchedResultsController实例被初始化,和这个获取结果控制器自动获得一个高速缓存。随后数据的加载几乎是瞬间的。


If a situation occurs where the fetch request associated with a fetched results controller needs to change, then it is vital that the cache be invalidated prior to changing the fetched results controller. You invalidate the cache by calling deleteCacheWithName:, which is a class level method on NSFetchedResultsController.

如果一个场景发生 获取请求使用一个获取结果控制器需要改变,高速缓存不可用在改变获取结果控制器之前是致命重要的,你通过调用deleteCacheWithName:不可用高速缓存,这是NSFetchedResultsController 的一个类方法。

Integrating Core Data at iOS Startup


The beginning of an application life cycle is subtly different in iOS and OS X.

When an OS X application takes an unusually long time to launch and becomes unresponsive, the operating system changes the cursor to indicate this state. The user can then decide to wait for the application to finish launching or shut down the application.

一个应用生命周期的开始是轻微不通的在iOS和 OS X。当一个OS X话费一个非正常的长时间去启动和变的无响应,操作系统改变光标去显示这个状态。然后用户决定去等待应用去完成启动或关闭这个应用。

In iOS, there is no such concept. If an app does not launch within a finite amount of time, the operating system terminates the application. Therefore, it is vital that an application complete the startup procedure as quickly as possible.


On the other hand, you want your application to be able to access data inside of Core Data as quickly as possible, which usually means initializing Core Data as one of the first steps in the application’s life cycle. Although atypical, Core Data occasionally takes longer than usual to complete its initialization.

Therefore, it is recommended that the startup sequence of an iOS app be broken into two phases, to avoid termination:


1 A minimal startup that indicates to the user that the application is launching 


2 Complete loading of the application UI once Core Data has completed its initialization 


Initializing Core Data in iOS

The first step is to change how the application:didFinishLaunchingWithOptions: method is implemented. In the application:didFinishLaunchingWithOptions: method consider initializing Core Data and doing very little else. If you are using a storyboard, you can continue to display the launch image during this method.

第一个是去改变 application:didFinishLaunchingWithOptions:方式如何被实现。在 application:didFinishLaunchingWithOptions:方法考虑初始化CD和做一点。如果你使用一个storyboard,你能继续去展示在这个方法期间去展示启动图片。

As part of the initialization of Core Data, assign the adding of the persistent store (NSPersistentStore) to the persistent store coordinator (NSPersistentStoreCoordinator) to a background queue. That action can take an unknown amount of time, and performing it on the main queue can block the user interface, possibly causing the application to terminate.


Once the persistent store has been added to the persistent store coordinator, you can then call back onto the main queue and request that the user interface be completed and displayed to the user.


Separating Core Data from the Application Delegate


Previously in iOS, the Core Data stack was typically initialized within the application delegate. However, doing so causes a significant amount of code to get muddled in with application life cycle events.


It is recommended that the Core Data stack be created within its own top-level controller object and that the application delegate initialize that controller object and hold a reference to it. This action will promote the consolidation of the Core Data code within its own controller and keep the application delegate relatively clean. This isolated controller design is shown in detail in Initializing the Core Data Stack.

建议CD栈被创建在它自己顶层控制器对象内和应用代理初始化那个控制器对象和有一个引用指向它。这个动作将提高CD代码在它自己控制器的整合和保持应用代理相对干净。这个被分离控制器设计被展示在initializing the Core Data Stack.

To integrate the code from the Initializing the Core Data Stack section into an iOS app, add a property to the application delegate and initialize the controller in the applicationDidFinishLaunching lifecycle method:

去整合代码从Initializing the Core Data Stack 组到一个iOS app.添加一个属性到应用代理和初始化这个控制器在applicationDidFinishLaunching生命循环方法中。


@interface AppDelegate : UIResponder <UIApplicationDelegate>


@property (strong, nonatomic) UIWindow *window;

@property (strong, nonatomic) DataController *dataController;




@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions


    [self setDataController:[[DataController alloc] init];

    // Basic User Interface initialization

    return YES;





class AppDelegate a href="" UIResponder /a a href="" UIApplicationDelegate /a  {


    var window a href="" UIWindow /a ?

    var dataController a href="" DataController /a !


    func application(application a href="" UIApplication /a , didFinishLaunchingWithOptions launchOptions: [ a href="" NSObject /a a href="" AnyObject /a ]?) ->  a href="" Bool /a  {

        dataController = DataController()

        // Basic User Interface initialization

        return true


By initializing a separate controller object with a completion block, you have moved the Core Data stack out of the application delegate, but you still allow a callback to the application delegate so that the user interface can know when to begin requesting data.


Integrating Core Data and Storyboards


Core Data integrates well with Xcode’s Storyboards feature, which you use to build your UI. This integration allows you to take advantage of the dependency injection pattern. Dependency injection is an inversion of control; it allows the caller of a framework to control the flow by passing references into the called object. Dependency Injection is one of the preferred patterns to be used with Cocoa development and specifically with iOS Cocoa development.


Integrating Core Data with a Storyboard Segue

使用一个Storyboard Segue 整合CD

A complex integration point for Core Data and storyboards is the transition between a table view displaying numerous data objects and a child view controller that presents the details of one of those items. Without using a storyboard, you accomplish this by overriding the UITableViewDelegate method tableView:didSelectRowAtIndexPath:. However, with a storyboard, this method should not be used, and the transition should be handled within the prepareForSegue:sender: method.

对CD和storyboards一个复杂整合点是转换在一个正在展示数据对象的 table view 和一个展示哪些项目中某一个细节的子view控制器。如果不使用storyboard,你通过从写UITableViewDelegate方法tableView:didSelectRowAtIndexPath:.然而,使用这个storyboard,这个方法不应该被使用,和转换应该被处理在prepareForSegue:sender:方法。

To demonstrate how you can integrate Core Data with a storyboard segue, consider the following example, which shows a primary view controller that is a table view with a list of employees. When one of those employees in that list is selected you will want to present a detail view of that employee. It is assumed that the view controller within the segue has a property to receive the selected NSManagedObject.

去证明你如何使用一个storyboard segue去整合CD,考虑下面的例子,它展示一个原始view 控制器是一个table view有一个雇员的列表。当雇员中的一个在那个列表被选择你将想去展示一个雇员的细节View。假设那个在segue中的view 控制器有一个属性去接受被选择的NSManagedObject.


@interface DetailViewController : UIViewController


@property (weak) AAAEmployeeMO *employee;




class DetailViewController a href="" UIViewController /a  {


    weak var employee a href="" AAAEmployeeMO /a ?



Next you implement the prepareForSegue:sender: method in the primary view controller to pass the appropriate NSManagedObject instance during the segue:

接着你实现prepareForSegue:sender:方法在主视图控制器中去传递适当的NSManagedObject 实例在segue期间:


#define CellDetailIdentifier @"CellDetailIdentifier"

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender


    id destination = [segue destinationViewController];

    if ([[segue identifier] isEqualToString:CellDetailIdentifier]) {

        NSIndexPath *indexPath = [[self tableView] indexPathForSelectedRow];

        id selectedObject = [[self fetchedResultsController] objectAtIndexPath:indexPath];

        [destination setEmployee:selectedObject];





let CellDetailIdentifier = "CellDetailIdentifier"

override func prepareForSegue(segue a href="" UIStoryboardSegue /a , sender a href="" AnyObject /a ?) {

    switch segue.identifier! {

    case CellDetailIdentifier:

        let destination = segue.destinationViewController as a href="" DetailViewController /a 

        let indexPath = tableView.indexPathForSelectedRow!

        let selectedObject = fetchedResultsController.objectAtIndexPath(indexPath) as a href="" AAAEmployeeMO /a 

        destination.employee = selectedObject


        print("Unknown segue: \(segue.identifier)")



Once the segue identifier (which is required to be unique per segue in a storyboard) is retrieved from the segue, you can safely assume what type of class the destination view controller is, and pass a reference to the selected Employee instance to the destination view controller. The destination view controller will then have the reference available to it during the loading portion of its life cycle and display the data associated with it. This is dependency injection in that the parent view controller is controlling the flow of the application by deciding which Employee instance to hand off to the destination view controller.

一旦segue ID(ID被要求在一个storyboard 中 每一个segue必须是唯一的)被从segue中获取,你能安全的呈现目的控制器是什么类型,和传递一个到被选择雇员实例的引用到目的控制器。这个目的控制器View然后持有那个对他有用的引用在它的生命循环加载期间和展示与之相关的数据。这个依赖注入在父类view 控制器通过决定那个雇员实例被传递到目的view控制器 来 控制应用的流向。

Managed Objects and References


References determine when managed objects are released from memory and also affect what causes them to be retained.


Weak References Between Managed Objects and the Context


Managed objects know what managed object context they’re associated with, and managed object contexts know what managed objects they contain. By default, though, the references between a managed object and its context are weak. This means that in general you cannot rely on a context to ensure the longevity of a managed object instance, and you cannot rely on the existence of a managed object to ensure the longevity of a context. Put another way, just because you fetched an object doesn’t mean it will stay around.


The exception to this rule is that a managed object context maintains a strong reference to any changed (inserted, deleted, and updated) objects until the pending transaction is committed (with a save:) or discarded (with a reset or rollback). Note that the undo manager may also keep strong references to changed objects—see Change Management.

这个规则的意外是***一个管理对象上下文保持一个强引用到任何改变(插入,删除,和更新)对象直到待定的转换被提交(使用 save:)或放弃(使用reset 或 rollback).注意撤销管理器可能也保持强引用到改变对象-参见 Change Management***.

Creating a Strong Reference Between Managed Objects and the Context


You can change a context’s default behavior so that it does keep strong references to its managed objects by setting the retainsRegisteredObjects property to true. Doing so makes the life of the managed objects dependent on the life of the context. This dependence can be convenient if you are caching smaller data sets in memory. For example, suppose the context controls a temporary set of objects that may persist beyond a single event cycle, such as a sheet in an OS X application or a modal view in an iOS application. Making managed objects dependent on the context can also be useful if you are using multiple threads and passing data between them — for example, if you are performing a background fetch and passing object IDs to the main thread. The background thread needs to keep strong references to the objects it prefetched for the main thread until it knows the main thread has actually used the object IDs to fault local instances into the main thread. Otherwise the objects may fall out of memory and need to be retrieved again from disk.

你能通过设置retainsRegisteredObjects属性为true改变一个上下文的默认行为以至于它保持一个强引用到它的管理对象.这样做管理对象的生命依赖在上下文的生命上。这个依赖非常方便如果你正在缓冲少量的数据在内存中。比如,假设上下文控制一个临时的可能保持在一个单独事件循环之外的对象集合,比如一个sheet在一个OS X应用中或一个modal view在一个iOS应用中。让管理对象依赖在上下文也很有用如果你使用很多线程和在它们之间传递数据-比如,你正在执行一个后台请求和传递对象的IDs到主线程。这个后台线程需要去保存强引用到那个它为主线程预取的对象直到它知道主线程已经真正的使用对象IDs去错误当地实例在主线程中。否则对象们可能从内存中废弃需要去被再次从磁盘中获取。

Use a separate container to keep strong references only to those managed objects you really need. You can use an array or dictionary, or an object controller (for example, an NSArrayController instance) that has strong references to the objects it manages. The managed objects you don’t need will then be deallocated when possible, such as when relationships are cleared (see Breaking Strong References Between Objects).

使用一个分开容器去保持一个强引用仅到哪些你真正需要的管理对象。你能使用一个数组或字典,或一个对象控制器(比如,一个NSArrayController 实例)它有强引用到它管理的对象。这个管理对象你不需要 将在可能的时候被释放,比如当关系被清除的时候(参见Breaking Strong References Between Objects).

If you have finished with a managed object context, or for some other reason you want to disconnect a context from its persistent store coordinator, do not set the context’s coordinator to nil.

Instead, simply relinquish ownership of the context and allow it to be deallocated normally.




[self setMyManagedObjectContext:nil];


myManagedObjectContext = nil

Breaking Strong References Between Objects


As opposed to the default behavior between managed objects and their managed object contexts, with relationships between managed objects, each object maintains a strong reference to the object or objects to which it is related. This relationship can cause strong reference cycles which in turn can cause objects to be held in memory long past their usefulness. To ensure that reference cycles are broken, when you are finished with an object, you can use the managed object context method refreshObject:mergeChanges: to turn the managed object into a fault.


You typically use refreshObject:mergeChanges: to refresh a managed object’s property values. If the mergeChanges flag is YES, the method merges the object’s property values with those of the object available in the persistent store coordinator. If the flag is NO, however, the method simply turns an object back into a fault without merging, which causes it to break strong references to related managed objects.


Before a managed object can be deallocated, any strong references to it must be removed, including those from outside of Core Data. See also Change Management.

在一个管理对象能被释放前,任何到它的强引用必须被移除,保护哪些在CD之外的。参见Change Management.

Strong References in Change and Undo Management


A context keeps strong references to managed objects that have pending changes (insertions, deletions, or updates) until the context is sent a save:, reset , rollback, or dealloc call, or the context is sent the appropriate number of undos to undo the change. If the calls to undo cause all changes to be undone on a particular object, the object’s strong reference will revert back to a weak reference.

一个上下文保持强引用到有未决定的改变(插入,删除,或更新)管理对象知道这个上下文被发送一个save:,reset,rollback,或dealloc调用,或这个上下文被发送了合适数量的撤销去撤销哪些改变。如果调用撤销造成所有改变到被撤销 在一个特殊对象,这个对象的强引用将被回滚到一个弱引用。

The undo manager associated with a context keeps strong references to any changed managed objects. By default, the context’s undo manager keeps an unlimited undo and redo stack. To limit your application's memory footprint, make sure that you scrub (using removeAllActions) the context’s undo stack when appropriate.

这个撤销管理者 和一个保持强引用到任何改变对象上下文 联系起来。默认情况,这个上下文的撤销管理者保持一个无限的撤销和重做栈。去限制你的应用的内存占用,确保你清除(使用removeAllActions)上下文的撤销栈在合适的时候。

If you do not intend to use Core Data’s undo functionality, you can reduce your application's resource requirements by setting the context’s undo manager to nil. This may be especially beneficial for background worker threads, as well as for large import or batch operations.


Ensuring Data Is Up to Date


If two applications are using the same data store, or a single application has multiple persistence stacks, it is possible for managed objects in one managed object context or persistent object store to get out of sync with the contents of the repository. If this occurs, you need to refresh the data in the managed objects, and in particular the persistent object store (the snapshots) to ensure that the data values are current.

如果两个应用在使用相同数据存储,或一个单独的应用有或多 持久栈,管理对象在一个管理对象上下文或持久对象存储和仓库的内容不是同步的。如果这个发生,你需要去刷新数据在管理对象中,和特别的这个持久对象存储(这个快照)去保证数据之是当前的。

Refreshing an Object


Managed objects whose property values are populated from the persistent store (realized objects), as well as pending updated, inserted, or deleted objects, are never changed by a fetch operation without developer intervention. For example, consider a scenario in which you fetch some objects and modify them in one editing context; meanwhile, in another editing context you edit the same data and commit the changes. If in the first editing context you then execute a new fetch that returns the same objects, you do not see the newly committed data values—you see the existing objects in their current in-memory state.


To refresh a managed object's property values, you use the managed object context method refreshObject:mergeChanges:. If the mergeChanges flag is YES, the method merges the object's property values with those of the object available in the persistent store coordinator. If the flag is set to NO, the method simply turns an object back into a fault without merging, which also causes strong references to other related managed objects to be broken. Thus you can use this method to trim the portion of your object graph that you want to hold in memory.

去刷新一个管理对象的属性值,你使用管理对象上下方法refreshObject:mergeChanges:.如果mergeChanges标示是YES,这个方法合并对象的属性值和在哪些可用的持久存储协调器中对象。如果标示是NO,这个方法这个方法仅仅转化对象到回到fault 而没有合并,这也会造成到其它相关管理对象 强引用 被打破。也就是你能使用这个方法去修剪部分你想去在保持在内存中的对象图的部分。

An object’s staleness interval is the time that has to pass until the store refetches the snapshot. The staleness interval only affects firing faults; moreover, it is only relevant for incremental (i.e. SQLite) stores. The other stores never refetch because the entire data set is kept in memory.


Merging Changes with Transient Properties


A transient property is a property on an object that is not persisted to disk. If you use refreshObject:mergeChanges: with the mergeChanges flag YES, then any transient properties are restored to their prerefresh value after awakeFromFetch is invoked. This means that, if you have a transient property with a value that depends on a property that is refreshed, the transient value may become out of sync.

一个临时属性是一个在对象上的不持久化到磁盘的属性。如果你使用refreshObject:mergeChanges:使用mergeChanges标示为YES,然后任何暂时属性被恢复到它们的上一个刷新值在awakeFromFetch 之后。这就意外着如果你有一个暂时属性 属性 有一个取决于一个被刷新属性的值,这个暂时值可能不是同步的。

Consider an application in which you have a Person entity with attributes firstName and lastName, and a cached transient derived property, fullName. (In practice it might be unlikely that a fullName attribute would be cached, but the example is easy to understand.) Suppose also that fullName is calculated and cached in a custom awakeFromFetch method.

考虑一个应用中你有一个 人 实体 有属性firstName 和 lastName,和一个缓存暂时衍生属性,fullName.(在实际中它可能不想一个fullName属性将被缓存,但是这个例子更好去理解。)假设这个fullName是被计算和缓存在一个自定义的awakeFromFetch方法中。

An Employee, currently named "Sarit Smith" in the persistent store, is edited in two managed object contexts:

一个雇员,当前名字是“Sarit Smith”在一个持久存储,被在两个管理对象上下文中编辑:

In context one, the corresponding instance's firstName is changed to "Fiona", which causes the cached fullName to be updated to "Fiona Smith", and the context is saved. 

在上下文一,这个对应实例的fristName被改变到“Fiona”,这造成被缓存的fullName被更新成“Fiona Smith”和上下文被保存。

In the persistent store, the employee is now “Fiona Smith”. 

In context two, the corresponding instance's lastName is changed to "Jones", which causes the cached fullName to be updated to "Sarit Jones". 

在持久存储,这个雇员现在是“Fiona Smith”.

在上下文2,这个相应实例的lastName被改变到“Jones”,这就造成被缓存fullName被更新到“Sarit Jones”.

The object is then refreshed with the
mergeChanges flag YES. The refresh fetches “Fiona Smith” from the store. The refresh updates the object as follows: 

这个对象然后使用mergeChanges标示YES刷新。这个刷新获取“Fiona Smith”从存储中。这个刷新 更新对象是如下的:

firstName was not changed prior to the refresh; the refresh causes it to be updated to the new value from the persistent store, so it is now "Fiona". 


lastNamewas changed prior to the refresh; so, after the refresh, it is set back to its modified value—"Jones". 


The transient value, fullName, was also changed prior to the refresh. After the refresh, its value is restored to "Sarit Jones". However, to be correct, it should be "Fiona Jones". 

这个暂时值,fullName,也是在刷新之前被改变。在刷新之后,它的值被恢复为“Sarit Jones”.然而,正确的是,它应该是“Fiona Jones”.

The example shows that, because prerefresh values are applied after awakeFromFetch, you cannot use awakeFromFetch to ensure that a transient value is properly updated following a refresh (or if you do, the value will subsequently be overwritten). In these circumstances, the best solution is to use an additional instance variable to note that a refresh has occurred and that the transient value should be recalculated.


Creating Managed Object Relationships


A managed object is associated with an entity description (an instance of NSEntityDescription) that provides metadata about the object and with a managed object context that tracks changes to the object graph. The object metadata includes the name of the entity that the object represents and the names of its attributes and relationships.

一个管理对象是和一个 提供关于对象和一个追寻到对象图表改变的管理对象上下文元数据 的实体描述(一个NSEntityDescription实例)相联系的。这个对象元数据包含 对象所呈现的他的属性和关系的名字实体的名字。


In a given managed object context, a managed object provides a representation of a record in a persistent store. In a given context, for a given record in a persistent store, there can be only one corresponding managed object, but there may be multiple contexts, each containing a separate managed object representing that record. Put another way, there is a to-one relationship between a managed object and the data record it represents, but a to-many relationship between the record and corresponding managed objects.



Core Data does not let you create relationships that cross stores. If you need to create a relationship from objects in one store to objects in another, consider using Weak Relationships (Fetched Properties).

CD不允许你创建跨越存储的关系。如果你需要去创建一个关系从一个存储到另一个存储中的对象,考虑使用Weak RelationShips(Fetched Properties).

Relationship Definitions in the Managed Object Model


There are a number of things you have to decide when you create a relationship. What is the destination entity? Is the relationship a to-one or a to-many? Is the relationship optional? If it’s a to-many, are there maximum or minimum numbers of objects that can be in the relationship? What should happen when the source object is deleted?


In an object model relationship, you have a source entity (for example, Department) and a destination entity (for example, Employee). You define a relationship between a source entity and a destination entity in the Relationship panel of the Data Model inspector for the source entity.


Figure 12-1Relationship pane in the Data Model inspector


Relationship Fundamentals


A relationship specifies the entity, or the parent entity, of the objects at the destination. This entity can be the same as the entity at the source (a reflexive relationship). Relationships do not have to reference a single entity type. If the Employee entity has two subentities, say Manager and Assistant, and Employee is not abstract, then a given department's employees may be made up of Employees (the primary entity), Managers (subentity of Employee), Assistants (subentity of Employee), or any combination thereof.

In the Type field of the Relationship pane, you can specify a relationship as being to-one or to-many, which is known as its cardinality.


 To-one relationships are represented by a reference to the destination object and to-many relationships are represented by mutable sets. Implicitly, to-one and to-many typically refer to one-to-one and one-to-many relationships respectively. A many-to-many relationship is one where both a relationship and its inverse are to-many. How you model a many-to-many relationship depends on the semantics of your schema. For details on this type of relationship, see Many-to-Many Relationships.

对一关系被通过一个到目的对象的引用呈现和对多关系被通过可变集合呈现。隐式的,对一 和 对多 分别就是说 一对一 和 一对多 关系。一个多对多关系是一个它的关系和它的可逆是对多的。你怎么模型化一个多对多关系由你图表的语义决定的。更多这个关系的类型的细节,参见Many-to-Many Relationships.

You can also put upper and lower limits on the number of objects at the destination of a to-many relationship. The lower limit does not have to be zero. You can specify that the number of employees in a department must be between 3 and 40. You also specify a relationship as either optional or not optional. If a relationship is not optional, then for it to be valid there must be an object or objects at the destination of the relationship.


Cardinality and optionality are orthogonal properties of a relationship. You can specify that a relationship is optional, even if you have specified upper and/or lower bounds. This means that there do not have to be any objects at the destination, but if there are, then the number of objects must lie within the bounds specified.


Creating Relationships Does Not Create Objects


It is important to note that simply defining a relationship does not cause a destination object to be created when a new source object is created. In this respect, defining a relationship is akin to declaring an instance variable in a standard Objective-C class. Consider the following example.



@interface AAAEmployeeMO : NSManagedObject


    @property (nonatomic, strong) AAAAddressMO *address;




class AAAEmployeeMO a href="" NSManagedObject /a  {

    @NSManaged address: AAAAddressMO?


If you create an instance of Employee, an instance of Address is not created unless you write code to cause it to happen. Similarly, if you define an Address entity, and a non-optional to-one relationship from Employee to Address, then simply creating an instance of Employee does not create a new Address instance. Likewise, if you define a nonoptional to-many relationship from Employee to Address with a minimum count of 1, then simply creating an instance of Employee does not create a new Address instance.

如果你创一个雇员的实例,一个地址实例没有被创建除非你写代码去让它发生。相似的,如果你定义了一个地址实体,和一个非可选的对一关系 从雇员到地震,然后简单创建一个雇员实例不创建一个新地址实例。同样,如果使用最小数量1你定义一个没有选择的对多关系从雇员到地址,然后简单创建雇员的实例不创建一个新地址实例。

Inverse Relationships


Most object relationships are inherently bidirectional. If a Department has a to-many relationship to the Employees who work in a Department, there is an inverse relationship from an Employee to the Department that is to-one. The major exception is a fetched property, which represents a weak one-way relationship—there is no relationship from the destination to the source. See Weak Relationships (Fetched Properties).

很多对象关系是固有双向的。如果一个部门有一个一对多关系到在这个部门工作的雇员,这里有一个反向关系从雇员到部门是对一的。主要的意外是获取属性,那展示一个弱 单路关系-哪里没有从目的到源的关系。参见Weak Relationships(Fetched Properties).

It is highly recommended that you model relationships in both directions, and specify the inverse relationships appropriately. Core Data uses this information to ensure the consistency of the object graph if a change is made (see Manipulating Relationships and Object Graph Integrity).

高度建议你在两个方向模型关系,和合适的明确反向关系。CD使用这个信息去保证对象图的一致性如果一个改变被创建(参见Manipulating Relationships and Object Graph Integrity).

Relationship Delete Rules


A relationship's delete rule specifies what should happen if an attempt is made to delete the source object. Note the phrasing if an attempt is made. If a relationship's delete rule is set to Deny, it is possible that the source object will not be deleted. Consider again a department's employees relationship, and the effect of the different delete rules.




If there is at least one object at the relationship destination (employees), do not delete the source object (department).

For example, if you want to remove a department, you must ensure that all the employees in that department are first transferred elsewhere (or fired!); otherwise, the department cannot be deleted.





Remove the relationship between the objects but do not delete either object.

This only makes sense if the department relationship for an employee is optional, or if you ensure that you set a new department for each of the employees before the next save operation.




Delete the objects at the destination of the relationship when you delete the


For example, if you delete a department, fire all the employees in that department at the same time.



No Action


Do nothing to the object at the destination of the relationship.

For example, if you delete a department, leave all the employees as they are, even if they still believe they belong to that department.

It should be clear that the first three of these rules are useful in different circumstances. For any given relationship, it is up to you to choose which is most appropriate, depending on the business logic. It is less obvious why the No Action rule might be of use, because if you use it, it is possible to leave the object graph in an inconsistent state (employees having a relationship to a deleted department).




第一上面前三个规则在不同情况下非常有用。对任何给定的关系,是由你来决定最合适的。由业务逻辑来决定。为甚么No Action可能被使用是不明显的,因为你使用它,可能遗留对象图表在一个不一致状态(雇员有一个关系到一个被删除部门)。

If you use the No Action rule, it is up to you to ensure that the consistency of the object graph is maintained. You are responsible for setting any inverse relationship to a meaningful value. This may be of benefit in a situation where you have a to-many relationship and there may be a large number of objects at the destination.

如果你使用No Action 规则,由你去保证对象图表的一致性被保持。你负责去设置任何反转关系到一个有意义的值。这可能在一个场景中有利就是你有一个 对多关系和在目的上有大数量的对象。

Manipulating Relationships and Object Graph Integrity


When you modify an object graph, it is important to maintain referential integrity. Core Data makes it easy for you to alter relationships between managed objects without causing referential integrity errors. Much of this behavior derives from the relationship descriptions specified in the managed object model.


When you need to change a relationship, Core Data takes care of the object graph consistency maintenance for you, so you need to change only one end of a relationship. This feature applies to to-one, to-many, and many-to-many relationships. Consider the following examples.

当你需要去改变一个关系,CD负责对象图表一致性为你,所以你仅仅需要去改变一个关系的末端。这个特征应用到 对一,对多, 多对多关系,考虑如下例子。

An employee’s relationship to a manager implies an inverse relationship between a manager and the manager’s employees. If a new employee is assigned to a particular manager, it is important that the manager be made aware of this responsibility. The new employee must be added to the manager’s list of reports. Similarly, if an employee is transferred from one department to another, a number of modifications must be made, as illustrated in Figure 12-2. The employee’s new department is set, the employee is removed from the previous department’s list of employees, and the employee is added to the new department’s list of employees.


Figure 12-2Inverse relationship maintaining integrity


Without the Core Data framework, you must write several lines of code to ensure that the consistency of the object graph is maintained. Moreover you must be familiar with the implementation of the Department class to know whether or not the inverse relationship should be set from the employee to the new department. This may change as the application evolves. Using the Core Data framework, all this can be accomplished with a single line of code:

没有CD框架,你必须写几行代码去确保对象图表的一致性被保持。更多的是你必须对部门类的实现熟悉 知道从雇员到新部门是否反转关系应该被设置。这个随着应用的演变可能改变。使用CD框架,所有这些使用一行代码就能使用。


anEmployee.department = newDepartment;


anEmployee.department = newDepartment

Alternatively, you can use:


[newDepartment addEmployeeObject:anEmployee];




Both of these have the same net effect: By referencing the application’s managed object model, the framework automatically determines from the current state of the object graph which relationships must be established and which must be broken.


Many-to-Many Relationships


You define a many-to-many relationship using two to-many relationships. The first to-many relationship goes from the first entity (the source entity) to the second entity (the destination). The second to-many relationship goes from the second entity (the original destination entity) to the first entity (the original source entity). You then set each to be the inverse of the other. (If you have a background in database management and this causes you concern, don't worry: if you use a SQLite store, Core Data automatically creates the intermediate join table for you.)

你使用两个对多关系定义一个多对多关系。第一个对多关系从第一个实体(源实体)到第二个实体(目的)。第二个 对多实体关系从第二个实体(原始目的实体)到第一个实体(原始的源实体)。你然后设置每一个都是另一个的反转。(如果你有背景在数据基础管理中这造成你担心,不用担心,如果你使用一个SQLite存储,CD自动创建中间连接表为你。)


You must define many-to-many relationships in both directions—that is, you must specify two relationships, each being the inverse of the other. You can’t just define a to-many relationship in one direction and try to use it as a many-to-many. If you do, you will end up with referential integrity problems.

你必须定义多对多关系在两个方向-也就是你必须明确两个关系,每一个是另一个的反转。你不能定义一个 对多 关系 在一个方向和试图去用它作为一个多对多关系。如果你这样做你将使用参照完整性问题结束。

This relationship configuration works even for relationships where an entity has a relationship back to itself (often called reflexive relationships). For example, if an employee can have more than one manager (and a manager can have more than one direct report), then you can define a to-many relationship directReports from the Employee entity to itself that is the inverse of another to-many relationship, managers, again from the Employee entity back to itself. This is illustrated in Figure 12-3.

这个关系配置工作甚至对一个实体有一个关系到他自己(通常被称作自反关系)关系。比如一个一个雇员有多个经理(和一个经理能有多个直接报告),然后你能定义一个 直接报告从雇员实体到它自己 是另一个 对多关系的反转,管理着再次从雇员实体会到它自己。这个在表12-3中被阐明。

Figure 12-3Example of a reflexive many-to-many relationship


Modeling a Relationship Based on Its Semantics


Consider the semantics of the relationship and how it should be modeled. A common example of a relationship that is initially modeled as a many-to-many relationship that’s the inverse of itself is “friends”. Although you are your cousin’s cousin whether the cousins like it or not, it’s not necessarily the case that you are your friend’s friend. For this sort of relationship, use an intermediate (join) entity. An advantage of the intermediate entity is that you can also use it to add more information to the relationship. For example, a FriendInfo entity might include some indication of the strength of the friendship with a ranking attribute, as shown in Figure 12-4.

考虑关系的语义和它应该被如何模型化。一个常见的一个关系的例子是初始化模型作为一个多对多关系是它自己的朋友的反转。尽管你是你表兄的表兄不管你表兄是否喜欢,那并不是必需的情况你是你的朋友的朋友。对这种关系的类型。使用一个中间实体。中间实体的优点是你也能使用它去添加更多信息到关系中。比如,一个 朋友关系实体 使用一个范围性熟悉 可能包含 友谊的强度的标示,就像表12-4.

Figure 12-4A model illustrating a friends relationship using FriendInfo as an intermediate entity


In this example, Person has two to-many relationships to FriendInfo: friends represents the source person’s friends, and befriendedBy represents those who count the source as their friend. FriendInfo represents information about one friendship, in one direction. A given instance notes who the source is, and one person they consider to be their friend. If the feeling is mutual, then there will be a corresponding instance where source and friend are swapped. There are several other considerations when dealing with this sort of model:

在这个例子中,人有两个对多关系到 FriendInfo,朋友关系展示了人的朋友,和befriendedBy 展示了哪些谁把 人作为它们的朋友。朋友信息 展示信息 关于 一个友谊,在一个方向,一个给实例显示了谁是源,和他们认为是他们的朋友的一个人。如果感觉是相互的,然后会有相对应的源和朋友是交换的实例。这里有一些其它需要考虑的当处理这个类型的模型:

To establish a friendship from one person to another, you have to create an instance of FriendInfo. If both people like each other, you have to create two instances of FriendInfo. 


To break a friendship, you must delete the appropriate instance of FriendInfo. 


The delete rule from Person to FriendInfo should be Cascade. That is, if a person is removed from the store, then the FriendInfo instance becomes invalid, so it must also be removed. 

从人到FriendInfo 的删除规则应该被及联。也就是,如果一个人被从存储中删除,然后FriendInfo实例变得无效,所以它也必须被移除。

As a corollary, the relationships from FriendInfo to Person must not be optional—an instance of FriendInfo is invalid if the
source or friend is null. 

作为一个必然结果,这个从FriendInfo 到 人 关系必须不是可选的-一个FrendInfo的实例是不可用的如果source 或friend 为空。

To find out who one person’s friends are, you have to aggregate all the friend destinations of the friends relationship, for example: 


NSSet *personsFriends = [aPerson valueForKeyPath:@"friends.friend"];


let personsFriends = aPerson.valueForKeyPath("friends.friend")

To find out who considers a given person to be their friend, you have to aggregate all the source destinations of the befriendedBy relationship, for example: 

去找到谁认为一个给定的人是他们的朋友,你不得不去聚集所有befriendBy关系的目的 source

NSSet *befriendedByPerson = [aPerson valueForKeyPath:@"befriendedBy.source"];


let befriendedByPerson = aPerson.valueForKeyPath("befriendedBy.source")

Cross-Store Relationships Not Supported


Be careful not to create relationships from instances in one persistent store to instances in another persistent store, as this is not supported by Core Data. If you need to create a relationship between entities in different stores, you typically use fetched properties. See the next section.


Weak Relationships (Fetched Properties)


Fetched properties represent weak, one-way relationships. In the employees and departments domain, a fetched property of a department might be Recent Hires. Employees do not have an inverse to the Recent Hires relationship. In general, fetched properties are best suited to modeling cross-store relationships, loosely coupled relationships, and similar transient groupings.

获取属性展示弱的,一个-方式 关系。在雇员和部门范围,一个部门的获取属性可能是 最近雇用 。雇员没有一个到最近雇佣关系的反转。通常来说,获取属性是最适合去模型化跨越存储的关系,松散连接关系,和类似暂时分组。

A fetched property is like a relationship, but it differs in several important ways:


Rather than being a direct relationship, a fetched property's value is calculated using a fetch request. (The fetch request typically uses a predicate to constrain the result.) 


A fetched property is represented by an array (NSArray), not a set (NSSet). The fetch request associated with the property can have a sort ordering, and thus the fetched property may be ordered. 

A fetched property is evaluated lazily, and is subsequently cached. 


Figure 12-5Adding a fetched property to an entity


In some respects you can think of a fetched property as being similar to a smart playlist, but with the important constraint that it is not dynamic. If objects in the destination entity are changed, you must reevaluate the fetched property to ensure it is up to date. You use refreshObject:mergeChanges: to manually refresh the properties—this causes the fetch request associated with this property to be executed again when the object fault is next fired.

You can use two special variables in the predicate of a fetched property, $FETCH_SOURCE and $FETCHED_PROPERTY. The source refers to the specific managed object that has this property, and you can create key paths that originate with that source, for example, LIKE [c] $FETCH_SOURCE.searchTerm. The $FETCHED_PROPERTY is the entity's fetched property description. The property description has a userInfo dictionary that you can populate with whatever key-value pairs you want. You can therefore change some expressions within a fetched property's predicate or any object to which that object is related.

在一些方面你能认为获取属性是和小播放列表,但是使用重要限制不是动态的。如果在目的实体的对象被改变,你必须重新评估它的属性去确保它被更新。你使用refreshObject:mergeChanges:去手动刷新属性-这导致和这个属性相联系的获取请求被再次执行当对象故障是下一个被触发。你能使用两个特殊变量在一个获取属性的谓词中,$FETCH_SOURCE和$FETCHED_PROPERTY。这个源指向一个明确的有这个属性的管理对象,和你能创建钥匙路径和源一起发生,比如, LIKE[c] $FETCH_searchTerm.这个$FETCHED_PROPERTY是实体的获取属性描述。这个属性描述有一个用户信息字典 你能用字典填充你相要的任何 键值 对。你能因此改变一些表达在一个获取属性谓词中或任何与那个属性相关的对象。

To understand how the variables work, consider a fetched property with a destination entity Author and a predicate of the form, ( LIKE [c] $FETCH_SOURCE.searchTerm) AND (favoriteColor LIKE [c] $FETCHED_PROPERTY.userInfo.color). If the source object had an attribute searchTerm equal to Cambridge, and the fetched property had a user info dictionary with a key color and value Green, then the resulting predicate would be ( LIKE [c] "Cambridge") AND (favoriteColor LIKE [c] "Green"). The fetched property would match any Authors at Cambridge whose favorite color is green. If you changed the value of searchTerm in the source object to Durham, then the predicate would be ( LIKE [c] "Durham") AND (favoriteColor LIKE [c] “Green").

去明白变量如何工作,考虑一个获取属性使用一个目的实体 作者和一个形式的谓词,( LIKE[c]  $FETCH_SOURCE.searchTerm)AND (favoriteColor LIKE [c] $FETCHED_PROPERTY.userInfo.color).如果源对象有一个属性serchTerm相当于剑桥,和获取属性有一个用户信息字典有一个color key 和一个绿色值,然后结果谓词将是( LIKE [c] “Cambridge”)AND (favoriteColor LIKE [c] “Green”).这个获取属性将匹配任何在剑桥的最喜欢颜色是绿色的作者。如果你改变在源对象中搜索项的值为Durham,然后谓词将变成( LIKE [c] “Durham”) AND (favoriteColor LIKE [c] “Green”).

The most significant constraint for fetched properties is that you cannot use substitutions to change the structure of the predicate — for example, you cannot change a LIKE predicate to a compound predicate, nor can you change the operator (in this example, LIKE [c]).

对获取属性来说最显著限制是你不能使用替换去改变谓词的结构-比如你不能改变一个LIKE谓词到一个复合谓词,你也不能改变操作(在这个例子,LIKE [c]).

Faulting and Uniquing


Faulting reduces your application’s memory usage by keeping placeholder objects (faults) in the persistent store. A related feature called uniquing ensures that, in a given managed object context, you never have more than one managed object to represent a given record.


Faulting Limits the Size of the Object Graph


Managed objects typically represent data held in a persistent store. In some situations a managed object may be a fault — an object whose property values have not yet been loaded from the external data store. Faulting reduces the amount of memory your application consumes. A fault is a placeholder object that represents a managed object that has not yet been fully realized, or a collection object that represents a relationship:

管理对象典型呈现在持久存储中的数据。在一些情景一个管理对象可能是一个断层- 一个对象它的属性值还没有被宠额外数据存储中加载。一个断层是一呈现一个还没有被完全实际化的管理对象占位符对象,或展示一个关系的集合对象:

A managed object fault is an instance of the appropriate class, but its persistent variables are not yet initialized. 


A relationship fault is a subclass of the collection class that represents the relationship. 


Faulting allows Core Data to put boundaries on the object graph. Because a fault is not realized, a managed object fault consumes less memory, and managed objects related to a fault are not required to be represented in memory at all.


To illustrate, consider an application that allows a user to fetch and edit details about a single employee. The employee has a relationship to a manager and to a department, and these objects in turn have other relationships. If you retrieve just a single Employee object from a persistent store, its manager, department, and reports relationships are initially represented by faults. Figure 13-1 shows an employee’s department relationship represented by a fault.


Figure 13-1A department represented by a fault


Although the fault is an instance of the Department class, it has not yet been realized—none of its persistent instance variables have yet been set. This means that not only does the department object consume less memory itself, but there’s no need to populate its employees relationship. If it were a requirement that the object graph be complete, then to edit a single attribute of a single employee, it would ultimately be necessary to create objects to represent the whole corporate structure.


Firing Faults


Fault handling is transparent—you do not have to execute a fetch to realize a fault. If at some stage a persistent property of a fault object is accessed, then Core Data automatically retrieves the data for the object and initializes the object . This process is commonly referred to as firing the fault. If you send the Department object a message to get, say, its name, then the fault fires—and in this situation Core Data executes a fetch for you to retrieve all the object's attributes. (See NSManagedObject for a list of methods that do not cause faults to fire.)


Core Data automatically fires faults when a persistent property (such as firstName) of a fault is accessed. However, firing faults individually can be inefficient, and there are better strategies for getting data from the persistent store (see Decreasing Fault Overhead). To deal efficiently deal with faults and relationships, see Fetching Managed Objects and Preventing a Fault from Firing.

CD自动触发断层当一个断层的持久存储属性(比如fristName)被访问。然而,单独触发断层是徒劳的,从更好的策略去从持久存储获取数据(参见Decreasing Fault Overhead).去高效的处理断层和关系,参见Fetching Managed Objects 和Preventing a Fault from Firing.

When a fault is fired, Core Data does not go back to the store if the data is available in its cache. With a cache hit, converting a fault into a realized managed object is very fast—it is basically the same as normal instantiation of a managed object. If the data is not available in the cache, Core Data automatically executes a fetch for the fault object; this results in a round trip to the persistent store to fetch the data, and again the data is cached in memory.


Whether or not an object is a fault simply means whether or not a given managed object has all its persistent attributes populated and is ready to use. If you need to determine whether an object is a fault, send it an isFault message without firing the fault (without accessing any relationships or attributes). If isFault returns NO, then the data must be in memory and therefore the object is not a fault. However, if isFault returns YES, it does not imply that the data is not in memory. The data may be in memory, or it may 

not, depending on many factors influencing caching.

一个对象是否是一个断层简单的意味着是否一个管理对象的所有属性全都产生出来和准备去使用。如果你需要去决定一个对象是否是断层,发送一个isFault信息而不用触发断层(不用访问任何关系和属性)。如果isFault返回NO,然后这个数据必须在内存中 因此这个对象不是一个断层。然而如果isFault返回YES,它没有在内存中实现哪些数据。这个数据可能在内存中,或它可能不在,取决于多少因素影响缓存。

Although the standard description method does not cause a fault to fire, if you implement a custom description method that accesses the object’s persistent properties, the fault will fire. You are strongly discouraged from overriding description in this way.


There is no way to load individual attributes of a managed object on an as-needed basis and avoid realizing (retrieving all property values of) the entire object. For patterns to deal with large attributes, see Binary Large Data Objects (BLOBs).

没油方法去加载一个管理对象的单独属性作为一个必要的基础而不用实例化(获取所有属性的值)整个对象,处理大属性的模式,参见Binary Large Data Objects(BLOBs).

Turning Objects into Faults


Turning a realized object into a fault can be useful in pruning the object graph, as well as ensuring that property values are current. Turning a managed object into a fault releases unnecessary memory, and sets its in-memory property values to nil. (see Reducing Memory Overhead andEnsuring Data Is Up to Date )

转化一个实际对象到一个断层在修剪对象图表很有用,也保证属性值是当前的。转化一个管理对象到断层释放不必要的内存,和设置它的内存中的属性值到nil.(参见Reducing Memory Overhead 和保证数据是最新的)

You can turn a realized object into a fault with the refreshObject:mergeChanges: method. If you pass NO as the mergeChanges argument, you must be sure that there are no changes to that object’s relationships. If there are, and you then save the context, you will introduce referential integrity problems to the persistent store.


When an object turns into a fault, it is sent a didTurnIntoFault message. You may implement a custom didTurnIntoFault method to perform various housekeeping functions; for example, see Ensuring Data Is Up to Date  ).



Core Data avoids the term unfaulting because it is confusing. There’s no “unfaulting” a virtual memory page fault. Page faults are triggered, caused, fired, or encountered. Of course, you can release memory back to the kernel in a variety of ways (using the functions vm_deallocate, munmap, or sbrk). Core Data describes this as “turning an object into a fault”.

CD避免项目的去断层因为它是困惑的。并没有“非断层”一个虚拟内存页断层。页断层被触发造成发射或遇到。当你页能释放内存回到内核中在很多方法中(使用functions vm_deallocate, munmap,或 sbrk).CD把着称为”转化一个对象到断层”。

Faults and KVO Notifications


When Core Data turns an object into a fault, key-value observing (KVO) change notifications are sent to the object’s properties. If you are observing properties of an object that is turned into a fault and the fault is subsequently realized, you receive change notifications for properties whose values have not in fact changed. See Key-Value Observing Programming Guide.


Although the values are not changing semantically from your perspective, the literal bytes in memory are changing as the object is materialized. The key-value observing mechanism requires Core Data to issue the notification whenever the values change according to the perspective of pointer comparison. KVO needs these notifications to track changes across key paths and dependent objects.

尽管值没有语义上的改变从你的观点,在内存中的字节数随着对象被物化而改变。这个键值检测机制需要CD去发布通知无论什么时候按照指针对比的观点值发生改变。KVO需要哪些通知去追中哪些改变通过key paths 和依赖对象。

Uniquing Ensures a Single Managed Object per Record per Context


Core Data ensures that—in a given managed object context—an entry in a persistent store is associated with only one managed object. The technique is known as uniquing. Without uniquing, you might end up with a context maintaining more than one object to represent a given record.

For example, consider the situation illustrated in Figure 13-2; two employees have been fetched into a single managed object context. Each has a relationship to a department, but the department is currently represented by a fault.

CD保证-在一个给定的管理对象上下文中-一个在持久存储中实体和仅一个关系对象相关。这个计算被称作 独特,没有独特,你可能最终用一个上下文保持多个对象去呈现给定的记录。比如考虑在表13-2中阐述场景;两个雇员已经被获取到一个单独的管理对象上下文。每个有一个关系到一个部分,但是部门目前被一个断层呈现。

Figure 13-2Independent faults for a department object


It would appear that each employee has a separate department, and if you called department on each employee — turning the Department faults into regular objects — you would have two separate Department objects in memory. However, if both employees belong to the same department (for example, Marketing), then Core Data ensures that (in a given managed object context) only one object representing the Marketing department is ever created. If both employees belong to the same department, their department relationships would both therefore reference the same fault, as illustrated in Figure 13-3.


Figure 13-3Uniqued fault for two employees working in the same department


Without uniquing, if you fetched all the employees and called department on each — thereby firing the corresponding faults — a new Department object would be created every time. This would result in a number of objects, each representing the same department, that could contain different and conflicting data. When the context is saved, it would be impossible to determine the correct data to commit to the store.


More generally, all the managed objects in a given context that refer to the Marketing Department object refer to the same instance—they have a single view of Marketing’s data—even if the Marketing Department object is a fault.



This discussion focuses on a single managed object context. Each managed object context represents a different view of the data. If the same employees are fetched into a second context, then they—and the corresponding Department object—are all represented by different objects in memory. The objects in different contexts may have different and conflicting data. It is precisely the role of the Core Data architecture to detect and resolve these conflicts at save time.


Object Validation


Cocoa provides a basic infrastructure for model value validation. However, it requires you to write code for all the constraints you want to apply. Core Data, on the other hand, allows you to put validation logic into the managed object model and specify most common constraints as opposed to writing validation logic in your code. You can specify maximum and minimum values for numeric and date attributes, maximum and minimum lengths for string attributes, and a regular expression that a string attribute must match. You can also specify constraints on relationships, such as making them mandatory or unable exceed a certain number.


If you do want to customize validation of individual properties, you use standard validation methods as defined by the NSKeyValueCoding protocol and described in Implementing Custom Property-Level Validation. To validate combinations of values (such as an array) and relationships, see Implementing Custom Interproperty Validation.

如果你想去自定义单独属性的验证,你使用标准验证方法被NSKeyValueCoding协议定义和描述在Implementing Custom Property-Level Validation.去验证值的组合(比如一个数组)和关系,参见Implementing Custom Interproperty  Validation.

How Validation Works in Core Data


How to validate is a model decision, when to validate is a user interface or controller-level decision. For example, a value binding for a text field might have its “validates immediately” option enabled. Moreover, at various times, inconsistencies are expected to arise in managed objects and object graphs.

An in-memory object can temporarily become inconsistent. 

如何去验证是模型的决定,什么时候去验证是用户界面或控制-层级决定。比如一个值绑定到一个文本区域可能有它的“立即验证”选项可用。更多在很多时间,不一致被期待去升高在管理对象和对象图表中。一个 在-内存对象能暂时不一致。

The validation constraints are applied by Core Data only during a save operation or upon request (you can invoke the validation methods directly at any time it makes sense for your application flow). Sometimes it is useful to validate changes as soon as they are made and to report errors immediately. Other times it makes sense to wait until a unit of work is completed before validation takes place. 


If managed objects were required to be always in a valid state, it would amongst other things force a particular workflow on the user. The ability to work with managed objects when they are not in a valid state also underpins the idea of a managed object context representing a scratch pad — in general you can bring managed objects onto the scratch pad and edit them however you wish before ultimately committing the changes or discarding them.


Implementing Custom Property-Level Validation


The NSKeyValueCoding protocol specifies the validateValue:forKey:error: method to provide general support for validation methods in a similar way to that in which valueForKey: provides support for accessor methods.

这个NSKeyValueCoding协议明确validatevalue:forKey:error方法去提供通用支撑为验证方法在一个相似方法 在那个方法valueForKey:提供支撑为访问方法。

NSManagedObject provides consistent hooks for implementing property (and interproperty) values. If you want to implement logic in addition to the constraints you provide in the managed object model, do not override validateValue:forKey:error:. Instead implement methods of the form validate<Key>:error:. If you do implement custom validation methods, you should typically not invoke them directly. Instead call the general method validateValue:forKey:error: with the appropriate key. This ensures that any constraints defined in the managed object model are also applied. 

If you were to call validate<Key>: error: instead, constraints may not be applied.


In the method implementation, you check the proposed new value, and if it does not fit your constraints, you return NO. If the error parameter is not null, you also create an NSError object that describes the problem, as illustrated in the following example. The example validates that the age value is greater than zero. If it is not, an error is returned.



- (BOOL)validateAge:(id*)ioValue error:(NSError**)outError


    if (*ioValue == nil) {

        return YES;


    if ([*ioValue floatValue] <= 0.0) {

        if (outError == NULL) {

            return NO;


        NSString *errorStr = NSLocalizedStringFromTable(@"Age must be greater than zero", @"Employee", @"validation: zero age error");

        NSDictionary *userInfoDict = @{NSLocalizedDescriptionKey: errorStr};

        NSError *error = [[NSError alloc] initWithDomain:EMPLOYEE_ERROR_DOMAIN code:PERSON_INVALID_AGE_CODE userInfo:userInfoDict];

        *outError = error;

        return NO;

    } else {

        return YES;




func validateAge(value a href="" AutoreleasingUnsafeMutablePointer /a < a href="" AnyObject /a ?>) throws {

    if value == nil {




    let valueNumber = value.memory as a href="" NSNumber /a 

    if valueNumber.floatValue > 0.0 {



    let errorStr = NSLocalizedString("Age must be greater than zero", tableName: "Employee", comment: "validation: zero age error")

    let userInfoDict = [NSLocalizedDescriptionKey: errorStr]

    let error = NSError(domain: "EMPLOYEE_ERROR_DOMAIN", code: 1123, userInfo: userInfoDict)

    throw error


The input value is a pointer to an object reference (an id *). This means that in principle you can change the input value. However, doing so is strongly discouraged, as there are potentially serious issues with memory management (see Key-Value Validation in Key-Value Coding Programming Guide). Moreover, do not call validateValue:forKey:error: within custom property validation methods. If you do, you will create an infinite loop when validateValue:forKey:error: is invoked at runtime.

这个输入值是一个指向一个对象的指针(一个id *).这意外着原则上你能改变输入的值。然而强烈不建议这样做,因为在内存管理(参见在 Key-Value Coding 编程指导中的  Key-Value Validation )上有潜在的严重问题。还有不要在自定义属性验证方法中调用validateValue:forKey:errorr:如果你这样做你会创建一个无限循环当validateValue:forKey:error被在运行时唤醒时。

Do not change the input value in a validate<Key>:error: method unless the value is invalid or uncoerced. The reason is that, because the object and context are now dirtied, Core Data may validate that key again later. If you keep performing a coercion in a validation method, it can produce an infinite loop. Similarly, also be careful if you implement validation and willSave methods that produce mutations or side effects—Core Data will revalidate those changes until a stable state is reached.

不要改变输入的值在一个validate<Key>:error:方法中除非值是不可用的或不正确的或非强迫的。着原因是,因为对象和上下文现在是污染的,CD可能在以后再一次验证那个key. 如果你保证执行一个强制在一个验证方法中,它可能创建一个无限循环。相似的,也要小心如果你实现验证和willSave方法产生突变和副作用-CD将再次验证哪些改变直到达到一个稳定状态。

Implementing Custom Interproperty Validation


It is possible for the values of all the individual attributes of an object to be valid and yet for the combination of values to be invalid. Consider, for example, an application that stores people’s age and whether or not they have a driving license. For a Person object, 12 might be a valid value for an age attribute, and YES is a valid value for a hasDrivingLicense attribute, but (in most countries at least) this combination of values would be invalid.

NSManagedObject provides additional opportunities for validation — update, insertion, and deletion—through the validateFor… methods such as validateForUpdate:. If you implement custom interproperty validation methods, you call the superclass’s implementation first to ensure that individual property validation methods are also invoked. If the superclass' implementation fails (that is, if there is an invalid attribute value), then you can do one of the following:

一个对象的所有独立属性被验证是有效的可是值的组合是无效的。考虑一下,比如,一个应用存储人的年龄和它们是否有一个驾照。对一个人对象,12可能是一个有效值对一个age属性,和YES是一个有效值对一个hasDrivingLicense 属性,但是(在很多国家至少)这个值的组合将是无效。NSManagedObject提供额外的机会为验证-更新,插入,和删除-尽管这个validateFor...方法比如validateForUpdate:.如果你实现自定义的内部验证方法,你首先调用父类的实现去保证单独属性验证方法也是唤醒的。如果父类实现失败(也就是,如果有一个不可用的属性值),然后你能做如下的事:

Return NO and the error created by the superclass' implementation. 

返回NO 和被父类实现创建的错误。

Continue to perform validation, looking for inconsistent combinations of values. 


If you continue to perform validation, make sure that any values you use in your logic are not themselves invalid in such a way that your code might itself cause errors. For example, suppose you use an attribute whose value is 0 as a divisor in a computation, but the attribute is required to have a value greater than 0. Moreover, if you discover further validation errors, you must combine them with the existing error and return a “multiple errors error” as described in Combining Validation Errors.

如果你去执行验证,保证在你的逻辑中你使用的任何值不是它们自身不可用在你的代码可能自己产生错误的方法中。比如假设你使用一个属性它的值是0作为一个除数在计算中,但是这个属性被要求有一个大于0的值。更多如果你发现更深验证错误,你必须组合它们和存在错误 和返回一个在Combining Validation Errors 中描述的组合了错误的错误。

The following example shows the implementation of an interproperty validation method for a Person entity that has two attributes, birthday and hasDrivingLicense. The constraint is that a person younger than 16 years cannot have a driving license. This constraint is checked in both validateForInsert: and validateForUpdate:, so the validation logic itself is factored into a separate method.

下面例子展示一个为一个有两个个属性,birthday 和 hasDrivingLicense 的人 实体内部属性验证方法的实现.限制是一个小于16年的人不能有驾照。这个限制被在validateForInsert:和validateForUpdate:中检测,所以这个验证逻辑它自己是分解到一个分开方法中国。

Listing 14-1Interproperty validation for a Person entity


- (BOOL)validateForInsert:(NSError **)error


    BOOL propertiesValid = [super validateForInsert:error];

    // could stop here if invalid

    BOOL consistencyValid = [self validateConsistency:error];

    return (propertiesValid && consistencyValid);


- (BOOL)validateForUpdate:(NSError **)error


    BOOL propertiesValid = [super validateForUpdate:error];

    // could stop here if invalid

    BOOL consistencyValid = [self validateConsistency:error];

    return (propertiesValid && consistencyValid);


- (BOOL)validateConsistency:(NSError **)error


    static NSCalendar *gregorianCalendar;

    NSDate *myBirthday = [self birthday];

    if (myBirthday == nil) {

        return YES;


    if ([[self hasDrivingLicense] boolValue] == NO) {

        return YES;


    if (gregorianCalendar == nil) {

        gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];


    NSDateComponents *components = [gregorianCalendar components:NSCalendarUnitYear fromDate:myBirthday toDate:[NSDate date] options:0];

    NSInteger years = [components year];

    if (years >= 16) {

        return YES;


    if (error == NULL) {

        //don't create an error if none was requested

        return NO;


    NSBundle *myBundle = [NSBundle bundleForClass:[self class]];

    NSString *drivingAgeErrorString = [myBundle localizedStringForKey:@"TooYoungToDriveError" value:@"Person is too young to have a driving license." table:@"PersonErrorStrings"];

    NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];

    [userInfo setObject:drivingAgeErrorString forKey:NSLocalizedFailureReasonErrorKey];

    [userInfo setObject:self forKey:NSValidationObjectErrorKey];

    NSError *drivingAgeError = [NSError errorWithDomain:EMPLOYEE_ERROR_DOMAIN code:NSManagedObjectValidationError userInfo:userInfo];

    if (*error == nil) { // if there was no previous error, return the new error

        *error = drivingAgeError;

    } else { // if there was a previous error, combine it with the existing one

        *error = [self errorFromOriginalError:*error error:drivingAgeError];


    return NO;



override func validateForInsert() throws {

    try super.validateForInsert()

    try self.validateConsistency()


override func validateForUpdate() throws {

    try super.validateForUpdate()

    try self.validateConsistency()


func validateConsistency() throws {

    guard let myBirthday = birthday else {



    if !hasDrivingLicense {




    let gregorianCalendar = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian)!


    let components = gregorianCalendar.components(.Year, fromDate: myBirthday, toDate: NSDate(), options:.WrapComponents)

    if components.year >= 16 {




    let errString = "Person is too young to have a driving license."

    let userInfo = [NSLocalizedFailureReasonErrorKey: errString, NSValidationObjectErrorKey: self]

    let error = NSError(domain: "EMPLOYEE_ERROR_DOMAIN", code: 1123, userInfo: userInfo)

    throw error


Combining Validation Errors


If there are multiple validation failures in a single operation, you create and return an NSError object with the code NSValidationMultipleErrorsError (for multiple errors error). You add individual errors to an array and add the array—using the key NSDetailedErrorsKey — to the user info dictionary in the NSError object. This pattern also applies to errors returned by the superclass's validation method. Depending on how many tests you perform, it may be convenient to define a method that combines an existing NSError object (which may itself be a multiple errors error) with a new one and returns a new multiple errors error.

如果在有很多验证失败在一个单独操作,你创建和使用代码NSValidationMultipleErrorsError(为组合错误的错误)返回NSError对象。你添加单个错误到一个数组和添加这个数组-使用NSDetailedErrorskey这个键-到NSError 对象的用户信息字典。这个模式也应到通过父类验证方法返回的错误。取决于你执行多少操作,去定义一个组合一个存在NSError 对象(也可能它自己就是一个组合错误的错误)和一个新的 然后返回一个新的组合错误方法可能是便利的。

The following example shows the implementation of a simple method to combine two errors into a single multiple errors error. How the combination is made depends on whether or not the original error was itself a multiple errors error. If the original error was already a multiple errors error, then the second error is added to it. Otherwise the two errors are combined together to create a new multiple errors error.



The combining of errors is not currently available in Swift.


Listing 14-2A method for combining two errors into a single multiple errors error

- (NSError *)errorFromOriginalError:(NSError *)originalError error:(NSError*)secondError


    NSMutableDictionary *userInfo = [NSMutableDictionary dictionary];

    NSMutableArray *errors = [NSMutableArray arrayWithObject:secondError];

    if ([originalError code] == NSValidationMultipleErrorsError) {

        [userInfo addEntriesFromDictionary:[originalError userInfo]];

        [errors addObjectsFromArray:[userInfo objectForKey:NSDetailedErrorsKey]];

    } else {

        [errors addObject:originalError];


    [userInfo setObject:errors forKey:NSDetailedErrorsKey];

    return [NSError errorWithDomain:NSCocoaErrorDomain code:NSValidationMultipleErrorsError userInfo:userInfo];


Change Management


If your application contains more than one managed object context and you allow objects to be modified in more than one context, you need to be able to reconcile the changes. This is a fairly common situation when an application is importing data from a network and the user can also edit that data.


Multiple Contexts in One Application


The object graph associated with any given managed object context must be internally consistent. If you have multiple managed object contexts in the same application, however, it is possible that each may contain objects that represent the same records in the persistent store, but whose characteristics are mutually inconsistent. In an employee application, for example, you might have two separate windows that display the same set of employees, but distributed between different departments and with different managers, as shown in Figure 15-1. Note how the manager relationship has moved from Lau to Weiss. Managed object context 1 still represents what is on disk, but managed object context 2 has changed.


Figure 15-1Managed object contexts with mutually inconsistent data values


Ultimately there can be only one truth, and differences between these views must be detected and reconciled when data is saved. When one of the managed object contexts is saved, its changes are pushed through the persistent store coordinator to the persistent store. When the second managed object context is saved, conflicts are detected using a mechanism called optimistic locking. How the conflicts are resolved depends on how you have configured the context.

最终只有一个能是真值,和哪些视图之间的不同必须被检测和一致当数据保存的时候。当一个管理对象上下文被保存,它的改变被通过持久存储协调器到推到持久存储。当第二个管理对象上下文被保存,冲突被检测到 使用一个叫开放式锁定的机制。冲突被如何解决取决于你已经配置的上下文是什么样的。

Conflict Detection and Optimistic Locking


When Core Data fetches an object from a persistent store, it takes a snapshot of its state. A snapshot is a dictionary of an object’s persistent properties—typically all its attributes and the global IDs of any objects to which it has a to-one relationship. Snapshots participate in optimistic locking. When the framework saves, it compares the values in each edited object’s snapshot with the then-current corresponding values in the persistent store.

***当CD获取一个对象从一个持久存储,它采取一个它(对象)的状态的快照。一个快照是一个对象的持久属性-通常它的所有属性和任何对象的有一个对一关系的全局IDs  的一个字典。快照参与开发锁定。当这个框架保存,它对比在每一个被编辑对象的快照和 以后-当前 相应在持久存储中的值。

If the values are the same, then the store has not been changed since the object was fetched, so the save proceeds normally. As part of the save operation, the snapshots' values are updated to match the saved data. 


If the values differ, then the store has been changed since the object was fetched or last saved; this represents an optimistic locking failure. The conflict must be resolved.


Choosing a Merge Policy


You can get an optimistic locking failure if more than one Core Data stack references the same external data store regardless of whether you have multiple Core Data stacks in a single application or you have multiple applications. It is possible that the same conceptual managed object will be edited in two persistence stacks simultaneously. You may want to ensure that subsequent changes made by the second stack do not overwrite changes made by the first, but other behaviors may be appropriate. Choose a merge policy for the managed object context that is suitable for your situation.


The default behavior is defined by an NSErrorMergePolicy property. This policy causes a save to fail if there are any merge conflicts. The save method returns an error with a userInfo dictionary that contains the key @"conflictList"; the corresponding value is an array of conflict records. You use the array to tell the user the differences between the values the user is trying to save and those current in the store. In this scenario the user must fix the conflicts (by refetching objects so that the snapshots are updated).


Alternatively, you specify a different policy. The NSErrorMergePolicy is the only policy that generates an error. Other policies — NSMergeByPropertyStoreTrumpMergePolicy, NSMergeByPropertyObjectTrumpMergePolicy, and NSOverwriteMergePolicy — allow the save to proceed by merging the state of the edited objects with the state of the objects in the store in different ways. The NSRollbackMergePolicy discards in-memory state changes for objects in conflict and uses the persistent store’s version of the objects’ state.




Automatic Snapshot Management


An application that fetches hundreds of rows of data can build up a large cache of snapshots. Theoretically, if enough fetches are performed, a Core Data-based application can contain all the contents of a store in memory. Clearly, snapshots must be managed in order to prevent this situation.

Responsibility for cleaning up snapshots rests with a mechanism called snapshot reference counting. This mechanism keeps track of the managed objects that are associated with a particular snapshot—that is, managed objects that contain data from a particular snapshot. When there are no remaining managed object instances associated with a particular snapshot (which Core Data determines by maintaining a list of strong references), Core Data automatically breaks the reference to the snapshot and it is removed from memory.


Synchronizing Changes Between Contexts


If you use more than one managed object context in an application, Core Data does not automatically notify one context of changes made to objects in another. In general, this is because a context is intended to be a scratch pad where you can make changes to objects in isolation, and you can discard the changes without affecting other contexts. If you do need to synchronize changes between contexts, how a change should be handled depends on the user-visible semantics you want in the second context, and on the state of the objects in the second context.


Registering with NSNotificationCenter


Consider an application with two managed object contexts and a single persistent store coordinator. If a user deletes an object in the first context (moc1), you may need to inform the second context (moc2) that an object has been deleted. In all cases, moc1 automatically posts an NSManagedObjectContextDidSaveNotification notification via the NSNotificationCenter that your application should register for and use as the trigger for whatever actions it needs to take. This notification contains information not only about deleted objects, but also about changed objects. You need to handle these changes because they may be the result of the delete. Most of these types of changes involve transient relationships or fetched properties.

考虑一个应用使用两个管理对象上下文和一个单独持久存储协调器。如果一个用户删除第一个上下文(moc1),你可能需要去通知第二个上下文(moc2)一个对象已经被删除。在所有情况中,moc1自动发送一NSManagedObjectContextDidSaveNotification 通知通过通知中心你的应用应该注册和作为任何它需要去采取动作的触发。这个通知不仅包含删除对象的信息,也管用改变对象。你需要去处理哪些改变因为它们可能是删除的结果。很多那种类型的改变包含展示属性或获取属性。

Choosing a Synchronization Strategy


When deciding how you want to handle your delete notification, consider:

What other changes exist in the second context? 

Does the instance of the object that was deleted have changes in the second context? 

Can the changes made in the second context be undone? 




These concerns are somewhat orthogonal, and what actions you take to synchronize the contexts depend on the semantics of your application. The following three strategies are presented in order of increasing complexity.


1 The object itself has been deleted in moc1 but has not changed in moc2. In that situation you do not have to worry about undo, and you can just delete the object in moc2. The next time moc2 saves, the framework will notice that you are trying to redelete an object, ignore the optimistic locking warning, and continue without error. 


2 If you do not care about the contents of moc2, you can simply reset it (using reset) and refetch any data you need after the reset. This will reset the undo stack as well, and the deleted object is now gone. The only issue here is determining what data to refetch. Do this before you reset by collecting the IDs (objectID) of the managed objects you still need and using those to reload once the reset has happened. You must exclude the deleted IDs, and it is best to create fetch requests with IN predicates to ensure faults will be fulfilled for deleted IDs. 

如果你不在乎moc2中的内容,你能简单的复位它(使用 reset)和获取任何你需要的数据在复位以后。这将也会复位撤销栈,被删除的对象现在不见了。这里的问题是决定去获取什么数据。在做这个之前你通过收集你依旧需要管理对象的IDs(objectID)复位和使用哪些去再次加载一次 复位就发生了。你必须排除删除的IDs,最好是去创建获取请求使用IN谓词去保证删除IDs断层将被完成。

3 If the object has changed in moc2, but you do not care about undo, your strategy depends on what it means for the semantics of your application. If the object that was deleted in moc1 has changes in moc2, should it be deleted from moc2 as well? Or should it be resurrected and the changes saved? What happens if the original deletion triggered a cascade delete for objects that have not been faulted into moc2? What if the object was deleted as part of a cascade delete? 


There are two workable options: 


Simply discard the changes by deleting the object in the moc that is receiving the notification. 


Alternatively, if the object is standalone, set the merge policy on the context to NSOverwriteMergePolicy. This policy will cause the changes in the second context to overwrite the delete in the database. 

it will cause all changes in
moc2 to overwrite any changes made in moc1


The preceding solutions are least likely to leave your object graph in an unsustainable state as a result of something you missed. If you find your application hitting merge issues that you are not able to resolve, this generally indicates an issue with the application’s architecture.

前面的解决最少可能性去 遗留你的对象图表在一个不可支持的状态 做为你错过一些事情的结果。如果你发现你的应用碰到你不能够解决的合并问题,这个通常标示着应用的架构出了问题。

Persistent Store Types and Behaviors

Core Data provides an in-memory persistent store and three disk-based persistent stores, as described in Table 16-1. The binary store (NSBinaryStoreType) is an atomic store, as is the XML store ( a href="" NSXMLStoreType /a ). You can also create custom store types, atomic and incremental. See Atomic Store Programming Topics and Incremental Store Programming Guide.


The XML store is not available in iOS.

Table 16-1Built-in persistent store types

Store type


Object graph in memory

Other factors

XML (atomic)



Externally parsable

Binary (atomic)











No on-disk storage required


Although Core Data supports SQLite as a store type, the store format—like those of the other native Core Data stores—is private. You cannot create a SQLite database using the native SQLite API and use it directly with Core Data, nor should you manipulate an existing Core Data SQLite store using native SQLite API. If you have an existing SQLite database, you need to import it into a Core Data store.

尽管CD支持SQLite作为一个存储方式,这个存储形式-像其他的原生CD存储-是私有的。你不创建一个SQLite数据基础使用原生SQLite API 然后和CD一起使用它,你也不应该使用原生的SQLite API 操纵一个存在CD SQLite存储.如果你有一个存在的SQLite 数据基库,你不需要去倒入它作为一个CD存储。

Given the abstraction that Core Data offers, there is typically no need to use the same store throughout the development process. It is common, for example, to use the XML store early in a project life cycle, because it is fairly human-readable and you can inspect a file to determine whether or not it contains the data you expect. In a deployed application that uses a large data set, you typically use an SQLite store, because it offers high performance and does not require that the entire object graph reside in memory. You might use the binary store store if you want store writes to be atomic.

给一个CD提供的抽象,没有必要去使用相同的存储在开发过程期间。它很常见,比如,去用XML存储在项目生命循环早期,因为他是相当易读的和你能检查一个文件去决定是否它包含你期望的数据。在一个被开发的使用大数据集合应用中,你使用一个SQLite存储,因为它提供高速执行和不需要整个对象图表在内存中。你可能使用二进制存储 如果你想让存储写入是原子性的。

Limitations of Persistent Store Security


Core Data makes no guarantees regarding the security of persistent stores from untrusted sources (as opposed to stores generated internally) and cannot detect whether files have been maliciously modified. The SQLite store offers slightly better security than the XML and binary stores, but it should not be considered inherently secure. Note also that it is possible for data archived in the metadata to be tampered with independently of the store data. To ensure data security, use a technology such as an encrypted disk image.

CD不保证关于从不信任的源(相对于 存储的内部产生的 )持久存储的安全和不能检测是否文件已经被恶意修改。这个SQLite存储提供比XML和二进制更安全轻便,但是它不能被认为是本身安全的。注意数据归档到数据元中也可能被存储数据的独立篡改。去保证数据安全,使用一个技术比如一个加密磁盘影像。

Fetch Predicates and Sort Descriptors


Fetching differs somewhat according to the type of store. In the XML, binary, and in-memory stores, evaluation of the predicate and sort descriptors is performed in Objective-C with access to all Cocoa functionality, including the comparison methods on NSString.


The SQLite store, on the other hand, compiles the predicate and sort descriptors to SQL and evaluates the result in the database itself. This is done primarily for performance, but it means that evaluation happens in a non-Cocoa environment, and so sort descriptors (or predicates) that rely on Cocoa cannot work. The supported sort selectors for SQLite are compare: and caseInsensitiveCompare:, localizedCompare:, localizedCaseInsensitiveCompare:, and localizedStandardCompare:. The latter is Finder-like sorting, and what most people should use most of the time. In addition you cannot sort on transient properties using the SQLite store.

这个SQLite存储,在其他方面,编译谓词和集合描述到SQL 和 评估结果在自己数据基础中。这个首先为了执行,但是它意外着评估发生在一个非Cocoa环境中,和依赖在Cocoa集合描述(或谓词)不能工作.对SQLite支持的方法集合有compare: 和caseInsensitiveCompare:,localizedCompare:,localizedCaseInsensitiveCompare:,和localizedStandardCompare:,后者是搜索排序,和大多数人在更多时候应该的。另外你不能使用一个SQLite存储排序一个展示属性。

There are additional constraints on the predicates you can use with the SQLite store:

你使用SQLite 存储 这有其他在谓词上的限制

You cannot necessarily translate arbitrary SQL queries into predicates. 

You can have only one to-many element in a key path in a predicate.
For example, no
toOne.toMany.toMany, or toMany.toOne.toMany type constructions (they evaluate to sets of sets) are allowed. As a consequence, in any predicate sent to the SQL store, there may be only one operator (and one instance of that operator) from ALL, ANY, and IN

你不能把SQL查询转化到谓词。你只能有一个 一到多元素在一个谓词的一个钥匙路径。比如,不能toOne.toMany.toMany,或toMany.toOne.toMany类型结构(它们预测到集合的集合)是允许的。作为一个后果,在任何发送到SQL存储的谓词中,可能只有操纵(和那个操纵的一个实例)从ALL,ANY,和IN。

CoreData supports a noindex: that can be used to drop indices in queries 

passed to SQLite. This is done primarily for performance reasons: SQLite uses a limited number of indices per query, and noindex: allows the user to preferentially specify which indexes should not be used. See NSPredicate documentation regarding function expressions.

CD支持一个noindex:能被用来去减少传递到SQLite中的请求的指数。这个首先是为了执行的原因:SQLite使用数量有限的指数每个请求,和noinex:允许用户去偏好明确那个指标不应该被使用。 参见关于功能表达的NSPredicate文档。 

SQLite-Supported File Systems


The SQLite store supports reading data from a file that resides on any type of file system. However, the SQLite store does not generally support writing directly to file systems that do not implement byte-range locking. For DOS file systems and for some NFS file system implementations that do not support byte-range locking correctly, SQLite will use <dbfile>.lock locking, and for SMB file systems it uses flock-style (file level) locking.

SQLite存储支持读数据从一个在任何文件系统类型中的文件。然而这个SQLite存储不通用的支持直接写入到没有实现 字节-范围 锁定的文件系统.比如DOS文件系统和一些NFS文件系统实现不正确的支持 字节-范围 锁定,SQLite将使用<dbfile>.lock锁定,和SMB文件系统它使用 群-风格(文件级别)锁定。

To summarize: Byte-range locking file systems have the best concurrent read/write support; these include HFS+, AFP, and NFS. File systems with simple file locking are also supported, but do not allow for as much concurrent read/write access by multiple processes. Simple file locking systems include SMB and DOS. The SQLite store does not support writing to WebDAV file-systems.

总结来说:字节-范围 锁定文件系统有最好同步读/写支持;其中包括 HFS+


SQLite File Size and Record Deletion

SQLite 文件大小和记录删除

Simply deleting a record from a SQLite store does not necessarily result in a reduction in the size of the file. If enough items are removed to free up a page in the database file, SQLite’s automatic database vacuuming will reduce the size of the file as it rearranges the data to remove that page. Similarly, the file size is reduced if you remove an item that itself occupies multiple pages (such as a thumbnail image).


An SQLite file is organized as a collection of pages. The data within those pages is managed through B-trees, not as simple fixed-length records. This format is more efficient for searching and for overall storage, because it allows SQLite to optimize how it stores both data and indexes in a single file. This format is also the foundation of SQLite’s data integrity (transaction and journaling) mechanism. However, the cost of this design is that some delete operations may leave holes in the file and impact read and write performance. If you delete some data and add other data, the holes left by the deleted data may be filled by the added data, or the file may be vacuumed to compact its data, whichever SQLite considers most appropriate based on the operations you’re performing.

一个SQLite文件是作为页的集合被管理的。在哪些页里的数据通过B-输来管理,和简单固定长度记录不同。这个形式是对查找和整体存储是更高效的,因为它允许SQLite 去优化它如何在一个单独文件中存储数据和索引。这个形式也是SQLite的数据完整性机制的基础。这个设计的开销就是一些删除操作可能遗留在文件上遗留一些洞和影响读和写的执行。如果你删除一些数据和添加另外数据,被删除留下的洞可能被添加数据填充,或这个文件可能被真空去紧凑它的数据,无论如何SQLite考虑最合适的给予你执行的操作。

Configuring Save Behavior for a SQLite Store

为一个SQLite 存储配置保存行为

When Core Data saves a SQLite store, SQLite updates just part of the store file. Loss of that partial update would be catastrophic, so ensure that the file is written correctly before your application continues. Unfortunately, doing partial file updates means that in some situations saving even a small set of changes to a SQLite store can take considerably longer than saving to, say, an XML store. For example, where saving to an XML file might take less than a hundredth of a second, saving to a SQLite store may take almost half a second. This data loss risk is not an issue for XML or binary stores. Because writes to these stores are typically atomic, it is less likely that data loss involves corruption of the file, and the old file is not deleted until the new has been successfully written.

当CD保存一个SQLite 存储,SQLite只更新存储文件的一部分。部分更新的丢失将是灾难性的,所以保证在你的应用继续前保证文件被正确写入。不幸的是部分的文件更新意味着在一些场景保存甚至一个小集合的改变到一个SQLite存储能消耗更久时间比XML存储。比如,保存到一个XML文件可能消耗的时间比百分之一秒还少,保存到一个SQLite 存储可能消耗几乎半秒时间。这个数据丢失风险对XML或二进制存储不是问题。因为写入到哪些存储是典型原子性的,



In OS X the fsync command does not guarantee that bytes are written, so SQLite sends a F_FULLFSYNC request to the kernel to ensure that the bytes are actually written through to the drive platter. This request causes the kernel to flush all buffers to the drives and causes the drives to flush their track caches. Without this, there is a significantly large window of time within which data will reside in volatile memory. If system failure occurs you risk data corruption.

在OS X这个fsync 命令不会保证字节被写入,所以SQLite发送一个F_FULLSFYNC请求到内核去取保指节被真正通过驱动盘写入。这个请求造成内核去刷新所有缓存到驱动盘和造成驱动去刷新它们追踪的高速缓存。没有这个,没有这个,将有一个显著大的时间窗口在其中数据将驻留在不稳定的内存中。如果系统失败发生你磁盘数据腐坏。

Changing a Store’s Type and Location


You can migrate a store from one type or location to another (for example, for a Save As operation) using the NSPersistentStoreCoordinator method migratePersistentStore:toURL:options:withType:error:. After invocation of this method, the original store is removed from the coordinator; thus the persistent store is no longer a useful reference. The method is illustrated in the following code fragment, which shows how you can migrate a store from one location to another. If the old store type is XML, then the example also converts the store to SQLite.



NSPersistentStoreCoordinator *psc = [[self managedObjectContext] persistentStoreCoordinator];

NSURL *oldURL = <#URL identifying the location of the current store#>;

NSURL *newURL = <#URL identifying the location of the new store#>;

NSError *error = nil;

NSPersistentStore *xmlStore = [psc persistentStoreForURL:oldURL];

NSPersistentStore *sqLiteStore = [psc migratePersistentStore:xmlStore






guard let psc = managedObjectContext.persistentStoreCoordinator else {

    fatalError("Failed to load persistent store")


let oldURL = NSURL(fileURLWithPath: "oldURL")

let newURL = NSURL(fileURLWithPath: "newURL")

guard let xmlStore = psc.persistentStoreForURL(oldURL) else {

    fatalError("Failed to reference old store")


do {

    try psc.migratePersistentStore(xmlStore, toURL: newURL, options:nil, withType:NSSQLiteStoreType)

} catch {

    fatalError("Failed to migrate store: \(error)")


To migrate a store, Core Data:


1 Creates a temporary persistence stack. 


2 Mounts the old and new stores. 


3 Loads all objects from the old store. 


4 Migrates the objects to the new store.
The objects are given temporary IDs, then assigned to the new store. The new store then saves the newly assigned objects (committing them to the external repository). 




5 Informs other stacks that the object IDs have changed (from the old to the new stores), which keeps the stack running after a migration. 


6 Unmounts the old store. 


7 Returns the new store. 


An error can occur if:


You provide invalid parameters to the method 


Core Data cannot add the new store 


Core Data cannot remove the old store 


In the latter two cases, you get the same errors that you would get if you called addPersistentStore: or removePersistentStore: directly. If an error occurs when the store is being added or removed, treat this as an exception, because the persistence stack is likely to be in an inconsistent state.

If a failure occurs during the migration itself, instead of an error you get an exception. In these cases, Core Data unwinds cleanly and there should be no repair work necessary. You can examine the exception description to determine what went wrong — possible errors range widely from "disk is full" and "permissions problems" to "The SQLite store became corrupted" and "Core Data does not support cross store relationships”.


Associating Metadata with a Store


A store’s metadata provides additional information about the store that is not directly associated with any of the entities in the store.

一个存储的元数据提供附加的 关于没有直接关联到在存储中任何实体的 存储的 信息。

The metadata is represented by a dictionary. Core Data automatically sets key-value pairs to indicate the store type and its UUID. You can create additional custom keys for your application, or provide a standard set of keys such as kMDItemKeywords to support Spotlight indexing (if you also write a suitable importer).


Be careful about what information you put into metadata. Spotlight imposes a limit to the size of metadata and replicating an entire document in metadata is probably not useful. However, if you create a URL to identify a particular object in a store (using URIRepresentation), the URL may be useful to include as metadata.

小心你放入到数据元中的信息。聚光灯添加一个元数据的大小施加一个限制和替换在元数据中的一个整个文档是没有用的。然而,如果你创建一个URL去定义一个特别对象在存储中(使用URIRepresentation), 这个URL去作为数据元包含可能有效的。

Getting the Metadata


There are two ways to get the metadata for a store:


Given an instance of a persistent store, get its metadata using the NSPersistentStoreCoordinator instance method metadataForPersistentStore:

给一个持久存储的一个实例,获取它的数据元使用 NSPersistentStoreCoordinator实例方法metadataForPersistentStore:.

Retrieve metadata from a store without the overhead of creating a persistence stack by using the NSPersistentStoreCoordinator class method, metadataForPersistentStoreOfType:URL:error:


There is an important difference between these approaches. The instance method, metadataForPersistentStore:, returns the metadata as it currently is in your program, including any changes that may have been made since the store was last saved. The class method, metadataForPersistentStoreOfType:URL:error:, returns the metadata as it is currently represented in the store itself. If there are pending changes to the store, the returned value may therefore be out of sync.

在哪些方法之间有很重要的不同。这个实例方法, metadataForPersistentStore:返回元数据是它当前在你程序中的,包含从上次存储开始任何可能已经创建的改变。这个类方法,metadataForPersistentStoreOfType:URL:error:,返回元数据是它当起呈现在存储中的自己。如果那里有未决定的改变到存储。返回的数据可能因此不是同步的。

Setting the Metadata


There are two ways you can set the metadata for a store:


Given an instance of a persistent store, set its metadata using the NSPersistentStoreCoordinator instance method, setMetadata:forPersistentStore:


Set the metadata without the overhead of creating a persistence stack by using the NSPersistentStoreCoordinator class method, setMetadata:forPersistentStoreOfType:URL:error:


There is again an important difference between these approaches. If you use setMetadata:forPersistentStore:, you must save the store (through a managed object context) before the new metadata is saved. If you use setMetadata:forPersistentStoreOfType:URL:error:, however, the metadata is updated immediately, and the last-modified date of the file is changed.

哪些方法之间有很多不同。如果你使用setMetadata:forPersistentStore:,你必须保存存储(通过一个管理对象上下文)在新数据元被保存之前。如果你使用setMetadata:forPersistentStoreOfType:URL:error:,然而这个数据被立即更新,文件的 上次-改变时间被改变。

This difference has particular implications if you use  NSPersistentDocument  on OS X. If you update the metadata using setMetadata:forPersistentStoreOfType:URL:error: while you are actively working on the persistent store (that is, while there are unsaved changes), then when you save the document you will see a warning, “This document's file has been changed by another application since you opened or saved it.” To avoid this, you should instead use setMetadata:forPersistentStore:. To find the document’s persistent store, you typically ask the persistent store coordinator for its persistent stores (persistentStores), and use the first item in the returned array to set the metadata. When you use setMetadata:forPersistentStoreOfType:URL:error: the action is treated as if the change occurred externally to your Core Data stack.

如果你用NSPersistentDocument在OS X上特别的影响。如果你更新数据元使用setMetaData:forPersistentStoreOfType:URL:error:当你积极的工作在持久存储(也就是当有未保存的改变时),然后当你保存文档你将看到一个警告,“这个文档的文件已经被另一个应用改变从你打开或保存它。”去避免这个你应该使用setMetadata:forPersistentStore:.去找到文档的持久存储,你询问持久存储协调器他的持久存储(persistentStores),和使用在返回数组中的第一个项目去设置数据元。当你使用setMetadata:forPersistentStoreOfType:URL:error这个动作被当作就像改变额外的发生到你的CD栈上。

Because Core Data manages the values for NSStoreTypeKey and NSStoreUUIDKey in the same metadata, make a mutable copy of any existing metadata before setting your own keys and values, as illustrated in the following code fragment:



NSURL *url = [NSURL fileURLWithPath:@"url to store"];

NSPersistentStore *store = [self.managedObjectContext.persistentStoreCoordinator persistentStoreForURL:url];

NSMutableDictionary *metadata = [[store metadata] mutableCopy];

metadata[@"MyKeyWord"] = @"MyStoredValue";

[store setMetadata:metadata];


let url = NSURL(fileURLWithPath: "url to store")

guard let store = managedObjectContext.persistentStoreCoordinator?.persistentStoreForURL(url) else {

    fatalError("Failed to retrieve store from \(url)")


var metadata = store.metadata

metadata["MyKeyWord"] = "MyStoredValue"

store.metadata = metadata



Concurrency is the ability to work with the data on more than one queue at the same time. If you choose to use concurrency with Core Data, you also need to consider the application environment. For the most part, AppKit and UIKit are not thread-safe. In OS X in particular, Cocoa bindings and controllers are not threadsafe — if you are using these technologies, multithreading may be complex.

并发是去使用数据在不止一个队列中在相同的时间去工作。如果你选择去使用CD去使用并非,你也需要去考虑应用环境。对大多数的部分,APPKit 和UIKit 不是 线程-安全。在OS X特殊点,Cocoa 绑定和控制是非 线程安全-如果你使用哪些技术,多线程可能很复杂。

Core Data, Multithreading, and the Main Thread


In Core Data, the managed object context can be used with two concurrency patterns, defined by NSMainQueueConcurrencyType and NSPrivateQueueConcurrencyType.

NSMainQueueConcurrencyType is specifically for use with your application interface and can only be used on the main queue of an application.


The NSPrivateQueueConcurrencyType configuration creates its own queue upon initialization and can be used only on that queue. Because the queue is private and internal to the NSManagedObjectContext instance, it can only be accessed through the performBlock: and the performBlockAndWait: methods.


In both cases, the initialization of the NSManagedObjectContextinstance is the same:



NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:<#type#>];


let moc = NSManagedObjectContext(concurrencyType:<#type#>)

The parameter being passed in as part of the initialization will determine what type of NSManagedObjectContext is returned.


Using a Private Queue to Support Concurrency


In general, avoid doing data processing on the main queue that is not user-related. Data processing can be CPU-intensive, and if it is performed on the main queue, it can result in unresponsiveness in the user interface. If your application will be processing data, such as importing data into Core Data from JSON, create a private queue context and perform the import on the private context. The following example shows how to do this:

通常避免在不是 用户-相关的 主队列上处理数据。数据处理能是CPU-密集型的,和如果被在主线程执行,它能在用户界面导致反应迟钝。如果你的应用将处理数据,比如从JSON导入数据到CD中,创建一个私有队列上下文和执行导入操作在私有上下文。下面的例子展示了如何去这样做:


NSArray *jsonArray = …; //JSON data to be imported into Core Data

NSManagedObjectContext *moc = …; //Our primary context on the main queue


NSManagedObjectContext *private = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];

[private setParentContext:moc];


[private performBlock:^{

    for (NSDictionary *jsonObject in jsonArray) {

        NSManagedObject *mo = …; //Managed object that matches the incoming JSON structure

        //update MO with data from the dictionary


    NSError *error = nil;

    if (![private save:&error]) {

        NSLog(@"Error saving context: %@\n%@", [error localizedDescription], [error userInfo]);





let jsonArray = … //JSON data to be imported into Core Data

let moc = … //Our primary context on the main queue


let privateMOC = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType)

privateMOC.parentContext = moc


privateMOC.performBlock {

    for jsonObject in jsonArray {

        let mo = … //Managed object that matches the incoming JSON structure

        //update MO with data from the dictionary


    do {


    } catch {

        fatalError("Failure to save context: \(error)")



In this example an array of data has been originally received as a JSON payload. You then create a new NSManagedObjectContext that is defined as a private queue. The new context is set as a child of the main queue context that runs the application. From there you call performBlock: and do the actual NSManagedObject creation inside of the block that is passed to performBlock:. Once all of the data has been consumed and turned into NSManagedObject instances, you call save on the private context, which moves all of the changes into the main queue context without blocking the main queue.


Passing References Between Queues


NSManagedObject instances are not intended to be passed between queues. Doing so can result in corruption of the data and termination of the application. When it is necessary to hand off a managed object reference from one queue to another, it must be done through NSManagedObjectID instances.

NSManagedObject实例不打算在队列之间传递。这样做能造成数据的损伤和杀死应用。当必须摒弃 传递一个管理对象引用从一个队列到另一个,必须通过NSManagedObjectID实例。

You retrieve the managed object ID of a managed object by calling the objectID method on the NSManagedObject instance.




Core Data is a rich and sophisticated object graph management framework capable of dealing with large volumes of data. The SQLite store can scale to terabyte-sized databases with billions of rows, tables, and columns. Unless your entities themselves have very large attributes or large numbers of properties, 10,000 objects is considered a fairly small size for a data set. When working with large binary objects, review Binary Large Data Objects (BLOBs).

CD是丰富的和精密的的对象图表管理框架能够处理大体积的数据。SQLite存储能扩展大小到T字节大小使用数十亿的行,表,和列。除非你的实体自身有很大属性或大数据的属性。1万个对象被认为是一个很小的数据集合。当使用大二进制对象,参见Binary Large Data Objects(BLOBs).

Overhead versus Functionality in Core Data


For a very simple application Core Data adds some overhead — compare a vanilla Cocoa document-based application with a Cocoa Core Data document-based application. However, even a simple Core Data-based application supports undo and redo, validation, object graph maintenance, and provides the ability to save objects to a persistent store. If you implemented this functionality yourself, it is quite likely that the overhead would exceed that imposed by Core Data. As the complexity of an application increases, the proportionate overhead that Core Data imposes typically decreases. At the same time the benefit typically increases. Implementing and supporting undo and redo in a large application, for example, is usually difficult.

对一个非常小应用CD添加一些开销—对比一个普通Cocoa 文档-基础 应用和一个Cocoa CD 文档-基础应用。然而,甚至一个简单CD-基础应用支持撤销和重做,验证,对象图表保持,和停供能力去保持对象到一个持久存储中。如果你自己实现这个功能,就好像这个开销超过CD施加的开销。随着一个应用的复杂的增加,CD施加的开销的比例也显著的减少。同时受益性显著的增加。实现和支持撤销和重组在一个大应用中,举例是通常困难的。

NSManaged Object Storage Mechanism


NSManagedObject uses an internal storage mechanism for data that is highly optimized. In particular, it leverages the information about the types of data that is available through introspecting the model. When you store and retrieve data in a manner that is compliant with key-value coding and key-value observing, it is likely that using NSManagedObject will be faster than any other storage mechanism — including for the simple get/set cases. In a modern Cocoa application that leverages Cocoa bindings, given that Cocoa bindings are reliant upon key-value coding and key-value observing, it would be difficult to build a raw data storage mechanism that provides the same level of efficiency as Core Data.

管理对象使用一个高度优化的内部存储机制为数据。它通过内观模型充分利用关于可用的数据的类型的信息。当你存储和获取数据用一种兼容了 键-值 和键-值观测 的方式,酒好像使用NSManagedObject将比任何其他存储机制更快-包括简单的获取/设置场景。在一个现代的利用了Cocoa绑定的Cocoa应用,该那个Cocoa绑定依赖于 键-值 编码和 键-值观察,去建造一个能提供和CD相同效率层级的原始数据存储机制将是困难的。

Fetching Managed Objects


Each round trip to the persistent store (each fetch) incurs an overhead, both in accessing the store and in merging the returned objects into the persistence stack. Avoid executing multiple requests if you can instead combine them into a single request that will return all the objects you require. You can also minimize the number of objects you have in memory.


Fetch Predicates

How you use predicates can significantly affect the performance of your application. If a fetch request requires a compound predicate, you can make the fetch more efficient by ensuring that the most restrictive predicate is the first, especially if the predicate involves text matching (contains, endsWith, like, and matches). Correct Unicode searching is slow. If the predicate combines textual and nontextual comparisons, then it is likely to be more efficient to specify the nontextual predicates first, for example, (salary > 5000000) AND (lastName LIKE 'Quincey') is better than (lastName LIKE 'Quincey') AND (salary > 5000000). For more about creating predicates, see Predicate Programming Guide.


你如何使用谓词能显著的影响你的应用的执行。如果一个获取请求查询一个复合谓词,你能通过保证最具限制性的谓词是第一个让获取更高效,特别如果谓词包含文本匹配(contains,endsWith,like,和matches).正确的单一编码搜索是慢的。如果谓词组合了文本和非文本的对比,然后去明确非文本谓词首先是更高效的,比如(salary>5000000)AND (lastName LIKE ‘Quincey’)比(lastName LIKE ‘Quincey’)AND (salary > 5000000).更多关于创建谓词参见Predicate Programming Guide.

Fetch Limits


You can set a limit to the number of objects a fetch will return using the method setFetchLimit:, as shown in the following example:



NSFetchRequest *request = [[NSFetchRequest alloc] init];

[request setFetchLimit:100];


let request = NSFetchRequest()

request.fetchLimit = 100

If you are using the SQLite store, you can use a fetch limit to minimize the working set of managed objects in memory, and so improve the performance of your application.


If you need to retrieve many objects, you can make your application appear more responsive by executing multiple fetches. In the first fetch, you retrieve a comparatively small number of objects—for example, 100—and populate the user interface with these objects. You then execute subsequent fetches to retrieve the complete result set via the fetchOffset method.


Preventing a Fault from Firing


Firing faults can be a relatively expensive process (potentially requiring a round trip to the persistent store), and you may wish to avoid unnecessarily firing a fault. You can safely invoke the following methods on a fault without causing it to fire: isEqual:, hash, superclass, class, self, zone, isProxy, isKindOfClass:, isMemberOfClass:, conformsToProtocol:, respondsToSelector:, description, managedObjectContext, entity, objectID, inserted, updated, deleted, and isFault.


Because isEqual: and hash do not cause a fault to fire, managed objects can typically be placed in collections without firing a fault. Note, however, that invoking key-value coding methods on the collection object might in turn result in an invocation of valueForKey: on a managed object, which would fire a fault. In addition, although the default implementation of description does not cause a fault to fire, if you implement a custom description method that accesses the object’s persistent properties, this will cause a fault to fire.

Note that just because a managed object is a fault, it does not necessarily mean that the data for the object is not in memory—see the definition for isFault.

因为isEqual:和hash不会造成一个断层触发,管理对象能放置到一个集合中而不用触发一个断层。注意唤醒一个 键-值 编码 方法在一个集合对象可能导致在一个管理对象上的valuedForKey:唤醒,这将触发一个断层。作为添加,尽管默认description的实现不造成一个断层触发,如果你实现一个自定义的访问对象的持久的描述方法,这将导致一个断层的触发。注意只是因为一个管理对象是一个断层,并补是一定意外着这个对象的数据不在内存中-参见isFault的定义。

Decreasing Fault Overhead


When you execute a fetch, Core Data fetches only instances of the entity you specify. In some situations (see Faulting Limits the Size of the Object Graph), the destination of a relationship is represented by a fault. Core Data automatically resolves (fires) the fault when you access data in the fault. This lazy loading of the related objects is much better for memory use, and much faster for fetching objects related to rarely used (or very large) objects. It can also, however, lead to a situation where Core Data executes separate fetch requests for a number of individual objects, which incurs a comparatively high overhead. For example, consider this model:

当你执行一个获取,CD仅仅获取你明确的实体的实例。在一些场景中(参见Faulting Limits the Size of the Object Graph),当一个关系的目的被一个断层呈现。CD自动的决定(触发)这个断层当你在断层中访问数据。这个相关数据的懒加载对内存使用很好,对获取很少用的或非常大的对象是更快的。它也能导致一个情景CD处理分开的请求是请求一批独立对象,这招致一个相对高开销。比如考虑如下模型:


You might fetch a number of Employees and ask each in turn for their Department's name, as shown in the following code fragment.



NSFetchRequest * employeesFetch = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];

// The request should include a predicate -- if you don't have a predicate here,

// you should probably just fetch all the Departments.

NSArray *fetchedEmployees = [moc executeFetchRequest:employeesFetch error:&error];

if (fetchedEmployees == nil) {

    NSLog(@"Error fetching: %@\n%@", [error localizedDescription], [error userInfo]);



for (Employee *employee in fetchedEmployees) {

    NSLog(@"%@ -> %@ department",;



let employeesFetch = NSFetchRequest(entityName: "Employee")

employeesFetch.relationshipKeyPathsForPrefetching = ["department"]

// The request should include a predicate -- if you don't have a predicate here,

// you should probably just fetch all the Departments.

do {

    let fetchedEmployees = try moc.executeFetchRequest(employeeFetch) as! [ a href="" AAAEmployeeMO /a ]

    for employee in fetchedEmployees {

        print("\( -> \(")


} catch {

    fatalError("Failed to fetch employees: \(error)")


This code might lead to the following behavior:

Jack -> Sales [fault fires]

Jill -> Marketing [fault fires]

Benjy -> Sales

Gillian -> Sales

Hector -> Engineering [fault fires]

Michelle -> Marketing

Here, there are four round trips to the persistent store (one for the original fetch of Employees, and three for individual Departments). These trips represent a considerable overhead on top of the minimum two trips to the persistent store.


There are two techniques you can use to mitigate this effect—batch faulting and prefetching.


Batch Faulting


You can batch fault a collection of objects by executing a fetch request using a predicate with an IN operator, as illustrated by the following example. (In a predicate, self represents the object being evaluated—see Predicate Format String Syntax.)

你能批次断层一个集合的数据通过使用一个谓词和一个IN 操作 执行一个获取请求,就像下面的例子阐明的那样。(在一个谓词,自己展示对象被估值)-参见predicate Format String Syntax.)


NSArray *array = @[fault1, fault2, ...];

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"self IN %@", array];


let array = [fault1, fault2, ...]

let predicate = NSPredicate(format:"self in %@", array)

When you create a fetch request you can use the NSFetchRequest method setReturnsObjectsAsFaults: to ensure that managed objects are not returned as faults.




Prefetching is in effect a special case of batch-faulting, performed immediately after another fetch. The idea behind prefetching is the anticipation of future needs. When you fetch some objects, sometimes you know that soon after you will also need related objects which may be represented by faults. To avoid the inefficiency of individual faults firing, you can prefetch the objects at the destination.


You can use the NSFetchRequest method setRelationshipKeyPathsForPrefetching: to specify an array of relationship key paths to prefetch along with the entity for the request. For example, given an Employee entity with a relationship to a Department entity: If you fetch all the employees, for each employee, print out the employee’s name and the name of the department. You can avoid the possibility of a fault being fired for each department instance by prefetching the department relationship. This is illustrated in the following code fragment:

你能使用NSFetchRequest 方法 setRelationshipKeyPathsForPrefetching:去明确一数组的关系key paths 还有请求的实体到预获取。比如给一个雇员实体一个关系到一个部门实体:如果你获取所有的雇员,每一个雇员打印部门的名字和部门的名字。你能避免通过预获取部门管理的每一个部门实例 一个断层被触发的可能。


NSManagedObjectContext *moc = …;

NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];

[request setRelationshipKeyPathsForPrefetching:@[@"department"]];


let moc = …

let request = NSFetchRequest(entityName:"Employee")

fetchRequest.relationshipKeyPathsForPrefetching = [“department"]

If you know something about how the data will be accessed or presented, you can further refine the fetch predicate to reduce the number of objects fetched. Note, though, that this technique can be fragile — if the application changes and needs a different set of data, then you can end up prefetching the wrong objects.


For more about faulting, and in particular the meaning of the value returned from isFault, see Faulting and Uniquing.

更多关于断层,在特殊情况下从isFault返回的值有什么意思,参见Faulting and Uniquing.

Reducing Memory Overhead


Sometimes you need to use managed objects on a temporary basis, for example, to calculate an average value for a particular attribute. Loading a large number of objects into memory causes your object graph, and memory consumption, to grow. You can reduce the memory overhead by refaulting individual managed objects that you no longer need, or you can reset a managed object context to clear an entire object graph. You can also use patterns that apply to Cocoa programming in general. Follow these guidelines to reduce memory overhead:

有时你需要去使用管理对象在一个临时基础上使用管理对象,比如,去计算平均值为一个指定的属性。加载很多对象到内存中造成你的对象图表,和内存消耗,增加。你能减少内存消耗通过断层你不再需要的独立管理对象,或你能再次设置一个管理对象上下文去清除整个对象图表。你也能使用应用到Cocoa 通过的编程模式。遵守指导去减少内存开销:

Refault an individual managed object using the refreshObject:mergeChanges: method for NSManagedObjectContext. Doing so clears the object’s in-memory property values thereby reducing its memory overhead. (Note that the values will be retrieved on demand if the fault is again fired — see Faulting and Uniquing.) 

再次断层一个单独管理对象使用refreshObject:mergeChanges:方法为NSManagedObjectContext.这样做清除对象的在内存中的属性值来减少它的内存消耗(注意这个值将被获取在要求中如果断层再次触发-参见Faulting and Uniquing.)

When you create a fetch request, set includesPropertyValues to NO to reduce memory overhead by avoiding creation of objects to represent the property values. You should typically only do so, however, if you are sure that either you will not need the actual property data or you already have the information in the row cache. Otherwise you will incur multiple trips to the persistent store. 


Use the reset method of NSManagedObjectContext to remove all managed objects associated with a context, and start over as if you'd just created it. Note that managed objects associated with that context will be invalidated, and so you will need to discard any references to and refetch any objects associated with that context. 

If you iterate over a lot of objects, you may need to use local autorelease pool blocks to ensure temporary objects are deallocated as soon as possible. 


If you do not intend to use Core Data’s undo functionality, reduce your application's resource requirements by setting the context’s undo manager to nil. This may be especially beneficial for background worker threads, as well as for large import or batch operations. 

If you have lots of objects in memory, determine the owning references. Core Data does not by default keep strong references to managed objects (unless they have unsaved changes). Managed objects maintain strong references to each other through relationships, which can easily create strong reference cycles. You can break cycles by refaulting objects (again by using the refreshObject:mergeChanges: method of NSManagedObjectContext). 

如果你不用CD的撤销功能,减少你的应用的资源需求通过设置上下文的撤销管理者到nil.这个可能很有用对后台工作线程,还有大的输入或批操作。如果你有很多对象在内存中,决定拥有引用。CD不会默认保持强引用管理对象(除非它们有未保持的改变)。管理对象保持强引用到另一个通过关系,这很容易创建引用的循环。你能打破这个循环通过再次断层对象(再次使用NSManagedObjectContext的方法    refreshObject:mergeChanges:)。

Binary Large Data Objects (BLOBs)


If your application uses Binary Large Objects (BLOBs) such as image and sound data, you need to take care to minimize overheads. Whether an object is considered small or large depends on an application’s usage. A general rule is that objects smaller than a megabyte are small or medium-sized and those larger than a megabyte are large. Some developers have achieved good performance with 10MB BLOBs in a database. On the other hand, if an application has millions of rows in a table, even 128 bytes might be a CLOB (Character Large OBject) that needs to be normalized into a separate table.

In general, if you need to store BLOBs in a persistent store, use a SQLite store. The other stores require that the whole object graph reside in memory, and store writes are atomic (see Persistent Store Types and Behaviors), which means that they do not efficiently deal with large data objects. SQLite can scale to handle extremely large databases. Properly used, SQLite provides good performance for databases up to 100GB, and a single row can hold up to 1GB (although of course reading 1GB of data into memory is an expensive operation no matter how efficient the repository).

如果你的应用使用二进制大数据对象比如图片或声音数据,你需要去考虑最小化开销。一个对象是否被认定小或大取决于一个应用的使用。一个常见规则是一个对象比一兆小是小或中等大小和哪些大于一兆是大。一些开发者能完成很好执行使用10兆二进制大数据在数据基础中。另一方面如果一个应用在一个table中有百万行。128个字节甚至都可能成为一个CLOB(字符大对象)需要去呗正常化到分开的table. 通常如果你需要去存储BLOB在一个持久存储中,使用一个SQLite能去处理非常大的数据库。其他存储需要整个对象图表在内存中,和存储写入是原子性的(参见Persistent Store Types 和Behaviors),这意味着它们不是高效处理大数据对象。SQLite能为大到100GB的数据库提供高执行,和一个单独行能处理1GB(尽管读取1GB数据到内存中是一个消耗的操作不管属性多么高效)。

A BLOB often represents an attribute of an entity—for example, a photograph might be an attribute of an Employee entity. For small to modest BLOBs (and CLOBs), create a separate entity for the data and create a to-one relationship in place of the attribute. For example, you might create Employee and Photograph entities with a one-to-one relationship between them, where the relationship from Employee to Photograph replaces the Employee's photograph attribute. This pattern maximizes the benefits of object faulting (see Faulting and Uniquing). Any given photograph is only retrieved if it is actually needed (if the relationship is traversed).

一个BLOB通常展示一个属性的一个属性-比如,一个图表可能是一个雇员实体的一个属性。为了更小的去适合BLOBs(和CLOBs),为数据创建一个分开的实体和创建一个 对一 关系在哪个属性中。比如你可能闯进雇员和图表实体使用一个 一对一 关系在它们之间,从雇员到图表取代了雇员的图标属性。这个模式最大化断层对象的利益(参见Faulting 和Uniquing).和给图表一个只能在珍重需要的时候获取(如果关系被贯穿)

It is better, however, if you are able to store BLOBs as resources on the file system, and to maintain links (such as URLs or paths) to those resources. You can then load a BLOB as and when necessary.


Analyzing Fetch Behavior with SQLite

You can use the user default to log to stderr the actual SQL sent to SQLite. (Note that user default names are case-sensitive.) For example, you can pass the following as an argument to the application:

你能使用用户默认的去打印到stderr发送到SQLite的SQL。(注意用户默认的名字是区分大小写的。)比如你能传递下面的内容作为参数到应用中: 1

Higher levels of debug numbers produce more information, although this is likely to be of diminishing utility.


The information the output provides can be useful when debugging performance problems—in particular it may tell you when Core Data is performing a large number of small fetches (such as when firing faults individually). The output differentiates between fetches that you execute using a fetch request and fetches that are performed automatically to realize faults.


Analyzing Application Behavior with Instruments


There are several Instruments probes specific to Core Data:


Core Data Fetches. Records invocations of executeFetchRequest:error:, providing information about the entity against which the request was made, the number of objects returned, and the time taken for the fetch. 


Core Data Saves. Records invocations of save: and the time taken to do the save. 


Core Data Faults. Records information about object and relationship fault firing. For object faults, Instruments records the object being faulted; for relationship faults, it records the source object and the relationship being fired. In both cases, it records the time taken to fire the fault. 

CD断层。纪录关于对象 和 关系断层触发的纪录信息。对对象断层,工具纪录对象被断层;对关系断层,它纪录源对象和被触发的关系。在两个情景中,它纪录触发断层需要的时间。

Core Data Cache Misses. Traces fault behavior that specifically results in file system activity — the instrument indicates that a fault was fired for which no data was available — and records the time taken to retrieve the data. 


All the instruments provide a stack trace for each event so that you can see what caused the event.


Additional Performance Information


Like all technologies, Core Data can be abused. You still need to consider basic Cocoa patterns, such as memory management. Also consider how you fetch data from a persistent store. Take into account factors not directly related to Core Data, such as overall memory footprint, object allocations, use and abuse of other API such as the key-value technologies, and so on. If you find that your application is not performing as well as you would like, use profiling tools such as Instruments to determine where the problem lies. See Performance in the Mac Developer Library.

就像所有的技术CD能被滥用。你依旧需要去考虑疾病的Cocoa模式,比如内存管理。也考虑你如何从持久存储获取数据。计入账号因素不直接联系到CD,比如总的内存占用,对象内存分配,使用和滥用其他的接口比如键-值技术,等等。如果你发现你的应用没有你期待的执行效果,使用分析工具比如去决定问题在什么地方。参见在Mac 开发者 库中的 Performance 

Troubleshooting Core Data


Core Data builds on functionality provided by other parts of Cocoa. When diagnosing a problem with an application that uses Core Data, take care to distinguish between problems that are specific to Core Data and those that stern from an error with another framework or that are architecture-related. Poor performance, for example, may not be a Core Data problem, but instead due to a failure to observe standard Cocoa techniques of memory management or resource conservation. If a user interface does not update properly, this may be due to an error in how you have configured Cocoa bindings.


Object Life Cycle Problems


Merge errors


Problem: You see the error message, "Could not merge changes".

Cause: Two different managed object contexts tried to change the same data. This is also known as an optimistic locking failure.

Remedy: Either set a merge policy on the context, or manually (programmatically) resolve the failure. You can retrieve the currently committed values for an object using committedValuesForKeys:, and you can use refreshObject:mergeChanges: to refault the object, so that when it is next accessed, its data values are retrieved from its persistent store.

问题:你看到错误信息:“Could not merge changes”.


这也就是正相关锁失败补救:在上下文设置一个合并策略,或手工(编码方式)解决失败。你能使用committedValuesForKeys: 获取当前对象的提交值和你能用refreshObject:mergeChanges:去再次断层这个对象,所以当它下次被访问,它的数据值被从它的持久对象获取。

Assigning a managed object to a different store


Problem: You see an exception that looks similar to this example.

<NSInvalidArgumentException> [<MyMO 0x3036b0>_assignObject:toPersistentStore:]:

Can’t reassign an object to a different store once it has been saved.


Cause: The object you are trying to assign to a store has already been assigned and saved to a different store.


Remedy: To move an object from one store to another, you must create a new instance, copy the information from the old object, save it to the appropriate store, and then delete the old instance.


Fault cannot be fulfilled


Problem: You see the error message, "Core Data could not fulfill a fault”.

问题:你看到错误信息,”Core Data could not fulfill a fault”

Cause: The object that Core Data is trying to realize has been deleted from the persistent store.


Remedy: Discard this object by removing all references to it.


Details: This problem can occur in at least two situations:



You started with a strong reference to a managed object from another object in your application. 


You deleted the managed object through the managed object context. 

You saved changes on the object context. 

At this point, the deleted object has been turned into a fault. It isn’t destroyed because doing so would violate the rules of memory management. 


Core Data will try to realize the faulted managed object but will fail to do so because the object has been deleted from the store. That is, there is no longer an object with the same global ID in the store.



You deleted an object from a managed object context. 


The deletion failed to break all relationships from other objects to the deleted object. 


You saved changes. 


At this point, if you try to fire the fault of a relationship from another object to the deleted object, it may fail, depending on the configuration of the relationship, which affects how the relationship is stored.


The delete rules for relationships affect relationships only from the source object to other objects (including inverses). Without potentially fetching large numbers of objects, possibly without reason, there is no way for Core Data to efficiently clean up the relationships to the object.


Keep in mind that a Core Data object graph is directional. That is, a relationship has a source and a destination. Following a source to a destination does not necessarily mean that there is an inverse relationship. So, in that sense, you need to ensure that you are properly maintaining the object graph across deletes.


Core Data uses inverse relationships to maintain referential integrity within the data model. If no inverse relationship exists and an object is deleted, you will be required to clean up that relationship manually.


In practice, a well-designed object graph does not require much manual post-deletion clean-up. Most object graphs have entry points that in effect act as a root node for navigating the graph, and most insertion and deletion events are rooted at those nodes just like fetches. This means that delete rules take care of most of the work for you. Similarly, because smart groups and other loosely coupled relationships are generally best implemented with fetched properties, various ancillary collections of entry points into the object graph generally do not need to be maintained across deletes, because fetched relationships have no notion of permanence when it comes to objects found through the fetched relationship.


Managed object invalidated


Problem: You see an exception that looks similar to this example:

<NSObjectInaccessibleException> [<MyMO 0x3036b0>_assignObject:toPersistentStore:]:

The NSManagedObject with ID:#### has been invalidated.


Cause: Either you have removed the store for the fault you are attempting to fire, or the managed object's context has been sent a reset message.


Remedy: Discard this object by removing all references to it. If you add the store again, you can try to fetch the object again.


Class is not key-value coding-compliant

类不是键-值 编码兼容的

Problem: You see an exception that looks similar to the following example.

<NSUnknownKeyException> [<MyMO 0x3036b0> valueForUndefinedKey:]:

this class is not key value coding-compliant for the key randomKey.


Cause: Either you used an incorrect key, or you initialized your managed object with init instead of initWithEntity:insertIntoManagedObjectContext:.

原因:你使用了不正确的key,或你使用init初始化你的管理对象而不是 initWithEntity:insertIntoManagedObjectContext:.

Remedy: Use a valid key (check the spelling and case carefully—also review the rules for key-value coding compliance in Key-Value Coding Programming Guide). Ensure that you use the designated initializer for NSManagedObject (see initWithEntity:insertIntoManagedObjectContext:).

修复:用一个可用的键(检查拼写和 场景注意-也查看在Key-Value Coding Programming Guide 的键-值编码标准)。确保你使用指定初始化者为NSManagedObject (参见 initWithEntity:insertIntoManagedObjectContext:).

Entity class does not respond to invocations of custom methods


Problem: You define an entity that uses a custom subclass of NSManagedObject, then in code you create an instance of the entity and invoke a custom method, as illustrated in this code fragment:



NSManagedObject *entityInstance =

    [NSEntityDescription insertNewObjectForEntityForName:@"MyEntity"


[entityInstance setAttribute: newValue];


let entityInstance = NSEntityDescription.insertNewObjectForEntityForName("myEntity", inManagedObjectContext: moc)

entityInstance.attribute = newValue

You get a runtime error like this:

"2005-05-05 15:44:51.233 MyApp[1234] ***

    -[NSManagedObject setNameOfEntity:]: selector not recognized [self = 0x30e340]


Cause: In the model, you misspelled the name of the custom class for the entity.


Remedy: Ensure that the spelling of the custom class name in the model matches the spelling of the custom class you implement.

修复:保证在模型中在自定义类名的拼写 匹配你实现的自定义类的拼写。

Custom accessor methods are not invoked, and key dependencies are not obeyed


Problem: You define a custom subclass of NSManagedObject for a particular entity and implement custom accessors methods (and perhaps dependent keys). At runtime, the accessor methods are not called, and the dependent key is not updated.


Cause: In the model, you did not specify the custom class for the entity.

Remedy: Ensure that the model specifies the custom class name for the entity rather than NSManagedObject.



Problems with Fetching


SQLite store does not work with sorting

SQLite 存储不使用排序工作

Problem: You create a sort descriptor that uses a comparison method defined by NSString, such as the following:



NSSortDescriptor *mySortDescriptor = [[NSSortDescriptor alloc]

        initWithKey:@"lastName" ascending:YES



let mySortDescriptor = NSSortDescriptor(key: "lastName", ascending: true)

You then either use this descriptor with a fetch request or as one of an array controller's sort descriptors. At runtime, you see an error message that looks similar to the following:


NSRunLoop ignoring exception 'unsupported NSSortDescriptor selector:

        localizedCaseInsensitiveCompare:' that raised during posting of

        delayed perform with target 3e2e42 and selector ‘invokeWithTarget:'

Cause: Exactly how a fetch request is executed depends on the store—see Fetching Objects.

原因:一个获取是如果执行的取决于存储-参见Fetching Objects.

Remedy: If you are executing the fetch directly, do not use Cocoa-based sort operators—instead, sort the returned array in memory. If you are using an array controller, you may need to subclass NSArrayController, so that it will not pass the sort descriptors to the database but will instead do the sorting after your data has been fetched.


Problems with Saving


Cannot save documents because entity is null


Problem: You have a Core Data document-based application that is unable to save. When you try to save the document you get an exception:

问题:你有一个CD 文档—基础不能保存的应用。当你尝试去保存文档你获得一个异常

Exception raised during posting of notification.  Ignored.  exception: Cannot perform operation since entity with name 'Wxyz' cannot be found

Cause: This error is emitted by an instance of NSObjectController (or one of its subclasses) that is set in Entity mode but can’t access the entity description in the managed object model associated with the entity name specified in Interface Builder. In short, you have a controller in entity mode with an invalid entity name.

原因:这个错误被一个设置在实体中的但是不能够访问描述在管理对象模型中的 实体NSObjectController的实例使用明确在交互设置中的实体名发射(或它的子类的)。也就是你有一个在实体模型中的控制器有一个不可用的实体名。

Remedy: Select in turn each of your controllers in Interface Builder, and press Command-1 to show the inspector. For each controller, ensure you have a valid entity name in the Entity name field at the top of the inspector.


Exception generated in retainedDataForObjectID:withContext


Problem: You add an object to a context. When you try to save the document you get an error that looks like this:


[date] My App[2529:4b03] cannot find data for a temporary oid: 0x60797a0 <<x-coredata:///MyClass/t8BB18D3A-0495-4BBE-840F-AF0D92E549FA195>x-coredata:///MyClass/t8BB18D3A-0495-4BBE-840F-AF0D92E549FA195>

This exception is in -[NSSQLCore retainedDataForObjectID:withContext:], and the backtrace looks like this:

#1    0x9599a6ac in -[NSSQLCore retainedDataForObjectID:withContext:]

#2    0x95990238 in -[NSPersistentStoreCoordinator(_NSInternalMethods) _conflictsWithRowCacheForObject:andStore:]

#3    0x95990548 in -[NSPersistentStoreCoordinator(_NSInternalMethods) _checkRequestForStore:originalRequest:andOptimisticLocking:]

#4    0x9594e8f0 in -[NSPersistentStoreCoordinator(_NSInternalMethods) executeRequest:withContext:]

#5    0x959617ec in -[NSManagedObjectContext save:]

The call to _conflictsWithRowCacheForObject: is comparing the object you're trying to save with its last cached version from the database. Basically, it's checking to see if any other code (thread, process, or just a different managed object context) changed this object without your knowledge.

Core Data does not do this check on newly inserted objects because they could not have existed in any other scope. They haven't been written to the database yet.


Cause: You may have forced a newly inserted object to lose its inserted status and then changed or deleted it. This could happen if you passed a temporary object ID to objectWithID:. You may have passed an inserted object to another managed object context.


Remedy: There are a number of possible remedies, depending on the root cause:


Do not pass an inserted (not yet saved) object to another context. Only objects that have been saved can be passed between contexts. 

Do not invoke refreshObject: on a newly-inserted object. 

Do not make a relationship to an object that you never insert into the context. 


Ensure that you use the designated initializer for instances of NSManagedObject

保证你使用了指定初始化者为NSManagedObject 的实例。

Before you save (frame #5 in the stack trace), make sure that the context’s updatedObjects and deletedObjects sets should only have members whose object ID returns NO from isTemporaryID.

在你保存以前(frame #5 在栈追寻),确保上下文的updatedObjects和deletedObjects集合应该只有它从isTemporaryID返回的的对象ID是NO的成员。

Debugging Fetching


Use the user default setting to log to stderr the actual SQL statement sent to SQLite. (Note that user default names are case sensitive.) For example, you can pass the following as an argument to the application:

使用用户默认设置去打印到控制台真正的SQL发送给SQLite的语句(注意用户默认名字是区分大小写的。)比如,你能传递如下的值作为一个参数给你的引用 1

Higher levels of debug numbers produce more information, although using higher numbers is likely to be of diminishing utility.


The information the output provides can be useful when debugging performance problems—in particular it may tell you when Core Data is performing a large number of small fetches (such as when firing faults individually). Like file I/O, executing many small fetches is expensive compared to executing a single large fetch. For examples of how to correct this situation, see Preventing a Fault from Firing.

输入提供的信息能有用当调试执行问题-在特殊中它可能告诉你CD什么在执行很大数量的小获取(比如单独触发断层的时候)。就像I/O,执行很多小获取是昂贵的相比于执行一个单独的大获取。如何去纠正这个场景,参见Preventing a Fault From Firing.


Using for reverse engineering to facilitate direct access to the SQLite file is not supported. It is exclusively a debugging tool.

As this is for debugging, the exact format of the logging is subject to change without notice. You should not, for example, pipe the output into an analysis tool with the expectation that it will work on all OS versions.传输输出到一个分析工具

使用 为了逆向工程去方便直接访问到SQLite 文件是不支持的。这是一个唯一的调试工具。这是唯一的一个调试工具。因为这个是用来调试的准确的输出格式在不通知你会发生改变。你不应该传输输出结果到一个使用将在所有OS版本上工作的期望的分析工具

Managed Object Models


Your application generates the message "+entityForName: could not locate an NSManagedObjectModel”


Problem: The error states clearly the issue—the entity description cannot find a managed object model from which to access the entity information.


Cause: The model may not be included in your application resources. You may be trying to access the model before it has been loaded. The reference to the context may be nil.


Remedy: Be sure that the model is included in your application resources and that the corresponding project target option in Xcode is selected.

The class method you invoked requires an entity name and a managed object context, and it is through the context that the entity gets the model. Basically, the core data stack looks like:

managed object context ---> persistent store coordinator ---> managed object model



If the managed object model cannot be found, make sure of the following:


The managed object context is not nil


If you are setting the reference to the context in a
.nib file, make sure the appropriate outlet or binding is set correctly. 


If you are managing your own Core Data stack, make sure that the managed object context has an associated coordinator (setPersistentStoreCoordinator: after allocating). 

如果你管理你自己的CD栈,确保管理对象上下文有配合的协调器(setPersistentStoreCoordinator: 在分配以后)

The persistent store coordinator has a valid model. 


Bindings Integration


Many problems relating to bindings are not specific to Core Data, and are discussed in target=Troubleshooting Cocoa Bindings  . This section describes some additional problems that could be caused by the interaction of Core Data and bindings.


Cannot access contents of an object controller after a nib is loaded


Problem: You want to perform an operation with the contents of an object controller (an instance of NSObjectController , NSArrayController , or NSTreeController) after a .nib file has been loaded, but the controller's content is nil.

问题:你想使用一个对象控制器(NSObjectController, NSArrayController,或NSTreeController)的内容去执行一个操作在一个nib文件已经被加载以后,但是控制器的内容是空的。

Cause: The controller's fetch is executed as a delayed operation performed after its managed object context is set (by nib loading)—the fetch therefore happens after awakeFromNib and windowControllerDidLoadNib:.

原因:控制器的获取被执行作为一个延时操作在管理对象上下文被设置以后(通过nib 加载)-这个获取发生在awakeFromNib和windowControllerDidLoadNib:.之后

Remedy: Execute the fetch manually with fetchWithRequest:merge:error:. See Using Core Data with Cocoa Bindings.

修复:手工执行fetchWithRequest:merge:error:.参见Using Core Data with Cocoa Bindings.

Cannot create new objects with array controller


Problem: You cannot create new objects using an NSArrayController. For example, when you click the button assigned to the add: action, you get an error similar to the following:


2005-05-05 12:00:)).000 MyApp[1234] *** NSRunLoop

ignoring exception 'Failed to create new object' that raised

during posting of delayed perform with target 123456

and selector ‘invokeWithTarget:'

Cause: In your managed object model, you may have specified a custom class for the entity, but you have not implemented the class.


Remedy: Implement the custom class, or specify that the entity is represented by NSManagedObject.


A table view bound to an array controller doesn't display the contents of a relationship

一个被绑定到一个数组控制器上的table view 不显示 一个关系的内容:

Problem: You want to display the contents of a relationship in a table view bound to an array controller, but nothing is displayed and you get an error similar to the following:

问题:你想去展示关系的内容在一个绑定到数组控制器的table view 中,但是什么都没有显示和你得到和下面相似的一个错误

2005-05-27 14:13:39.077 MyApp[1234] *** NSRunLoop ignoring exception

'Cannot create NSArray from object <_NSFaultingMutableSet: 0x3818f0> ()

of class _NSFaultingMutableSet - consider using contentSet

binding instead of contentArray binding' that raised during posting of

delayed perform with target 385350 and selector 'invokeWithTarget:'

Cause: You bound the controller's contentArray binding to a relationship. Relationships are represented by sets.


Remedy: Bind the controller's contentSet binding to the relationship.


A new object is not added to the relationship of the object currently selected in a table view

一个新对象没有被添加到当在table view中的对象的关系上。

Problem: You have a table view that displays a collection of instances of an entity. The entity has a relationship to another entity, instances of which are displayed in a second table view. Each table view is managed by an array controller. When you add new instances of the second entity, they are not added to the relationship of the currently selected instance of the first.

问题:你有一个table view 它展示一个一个实体的实例的集合。这个实体有一个关系到另一个实体,

Cause: The two array controllers are not related. There is nothing to tell the second array controller about the first.


Remedy: Bind the second array controller's contentSet binding to the key path that specifies the relationship of the selection in the first array controller. For example, if the first array controller manages the Department entity, and the second array controller manages the Employee entity, then the contentSet binding of the second array controller should be [Department Controller].selection.employees.

修复:绑定第二个数组控制器的contentSet到 明确在第一个数组控制器中被选项的关系的key path。比如,如果第一个数组控制器管理部门实体,和第二个数组控制器管理雇员实体,然后这个第二个数组控制器的绑定contentSet应该是[Department Controller].selection.employees.

Table view or outline view contents not kept up-to-date when bound to an NSArrayController or NSTreeController object

table view 或大纲视图内容没有保持更新当绑定到一个NSArrayController 或 NSTreeController 对象

Problem: You have a table view or outline view that displays a collection of instances of an entity. As new instances of the entity are added and removed, the table view is not kept in sync.

问题:你有一个table view 或展示一个实体的实例的集合的大纲视图。一个实体的新实例被添加和删除,这个table view  美哟保持同步。

Cause: If the controller's content is an array that you manage yourself, then it is possible you are not modifying the array in a way that is KVO-compliant.

If the controller's content is fetched automatically, then you have probably not set the controller to "Automatically prepare content."

Alternatively, the controller may not be properly configured.

原因:如果控制器的内容是一个你通知你自己的数组,然后你没有使用KVO-遵守的方式去修改数组。如果控制器的内容被自动获取,然后你可能是没有设置控制器到“Automatically prepare content.” 还可能,控制器没有被合适的配置。

Remedy: If the controller's content is a collection that you manage yourself, then ensure you modify the collection in a way that is KVO-compliant. See target Troubleshooting Cocoa Bindings  .

修复:如果控制器的内容是一个你通知你自己的集合,然后确保你修改这个集合在遵守KVO-编译的方式。参见target Troubleshooot Cocoa Bindings.

If the controller's content is fetched automatically, set the "Automatically prepares content" switch for the controller in the Attributes inspector in Interface Builder (see also automaticallyPreparesContent). Doing so means that the controller will track inserts into and deletions from its managed object context for its entity.

如果控制器的内容被自动获取,在交互界面 建设(参见 automaticallyPrepareContent)的 属性检查器中设置这个“Automatically prepares content” 开关为控制器.这样做意外这个控制器将追寻从它的管理对象上下文插入或删除。

Also check to see that the controller is properly configured (for example, that you have set the entity correctly).


Frequently Asked Questions


Where is a managed object context created?


Where a managed object context comes from is entirely application-dependent. In a Cocoa document-based application using NSPersistentDocument, the persistent document typically creates the context, and gives you access to it through the managedObjectContext method.

管理对象上下文在那里创建是整个应用-决定的。在一个Cocoa 文档-基础 应用 使用NSPersistentDocument,这个持久文件通常创建这个上下文,和给你通过 managedObjectContext方法去访问它。

In a single-window application, if you create your project using the standard project assistant, the application delegate (the instance of the NSApplicationDelegate class) again creates the context, and gives you access to it through the managedObjectContext method. In this case, however, the code to create the context (and the rest of the Core Data stack) is explicit. It is written for you automatically as part of the template.

Do not use instances of subclasses of NSController directly to execute fetches. For example, do not create an instance of NSArrayController specifically to execute a fetch. Controllers are for managing the interaction between your model objects and your application interface. At the model object level, use a managed object context to perform the fetches directly.

在一个单-窗口应用中,如果你使用标准项目助理创建项目,这个应用代理(NSApplicationDelegate 类的实例)再次创建上下文,和让你去访问它通过managedObjectContext 方法。在这个场景中,代码去创建上下文(和CD栈的剩余)是明确的。它自动作为模版的一部分为你写入。不要用NSController 的子类的实例直接去执行获取。比如,不要创建一个NSArrayController的实例去执行一个获取。控制是为了管理你的模型对象和你的应用界面之间的交互。在模型对象层,使用管理对象去直接执行获取。

How do I initialize a store with default data?


There are two considerations here: creating the data, and ensuring the data is imported only once.


There are several ways to create the data.


Create a separate persistent store that contains the default data and include the store as an application resource. When you want to use it, either copy the whole store to a suitable location, or copy the objects from the defaults store to an existing store. 


For small datasets, create the managed objects directly in code. 

Create a property list or another file-based representation of the data, and store it as an application resource. When you want to use it, open the file and parse the representation to create managed objects. 


Do not use this technique in iOS, and only if absolutely necessary in OS X. Parsing a file to create a store incurs unnecessary overhead. It is much better to create a Core Data store yourself offline and use it directly in your application. 

不要在iOS中使用这个技术,在OS X中必须要用的时候使用,解析一个文件去创建一个存储招致不必要的消耗。去创建一个CD更好和直接去创建它在你的应用中。

There are also several ways to ensure that the defaults are imported only once:


If you are using iOS or creating an application for OS X that is not document-based, you can add a check on application launch to determine whether a file exists at the location you specify for the application’s store. If it doesn't, you need to import the data. 

If you are creating a document-based application using NSPersistentDocument, you initialize the defaults in initWithType:error:

如果你使用iOS或创建一个因为OS X不是文档-基础的,你能添加一个检查在应用启动中去决定是否一个文件存储于你明确给应用的存储的位置。如果它存在,你需要去导入数据。如果你创建一个文件-基础应用使用NSPersistentDocument,你在initWithType:error初始化这个默认值。

If there is a possibility that the store (hence file) might be created but the data not imported, then you can add a metadata flag to the store. You can check the metadata (using metadataForPersistentStoreWithURL:error: ) more efficiently than executing a fetch (and it does not require you to hard code any default data values).


How do I use my existing SQLite database with Core Data?

如何用CD去操作我的已经存在的SQLite 数据库?

You do not, unless you import your existing SQLite database into a Core Data store. Although Core Data supports SQLite as one of its persistent store types, the database format is private. You cannot create a SQLite database using the native SQLite API and use it directly with Core Data. If you have an existing SQLite database, you need to import it into a Core Data store. In addition, do not manipulate an existing Core Data-created SQLite store using the native SQLite API.

不可以,除非你导入你的存在的SQLite数据库到一个CD存储。尽管CD支持SQLite作为它的持久存储的一个类型。这个数据库的形式是私有的。你不能使用原生的SQLite 接口创建一个SQLite数据库和直接用CD操作它。如果你有一个存在SQLite 数据库,你需要去导入它到一个CD存储中。作为添加不要使用原生SQLite 接口 去 操作一个存储的CD-创建SQLite存储。

I have a to-many relationship from Entity A to Entity B. How do I fetch the instances of Entity B related to a given instance of Entity A?


You don’t. More specifically, there is no need to explicitly fetch the destination instances, you simply invoke the appropriate key-value coding or accessor method on the instance of Entity A. If the relationship is called widgets, then if you have implemented a custom class with a similarly named accessor method, you simply write:



NSSet *asWidgets = [instanceA widgets];


let asWidets = instanceA.widgets

Otherwise you use key-value coding:


NSMutableSet *asWidgets = [instanceA mutableSetValueForKey:@"widgets"];


let asWidgets = instanceA.mutableSetValueForKey("widgets")

How do I fetch objects in the same order I created them?


Objects in a persistent store are unordered. Typically you should impose order at the controller or view layer, based on an attribute such as creation date. If there is order inherent in your data, you need to explicitly model that.


How do I copy a managed object from one context to another?


First, note that in a strict sense you are not copying the object. You are conceptually creating an additional reference to the same underlying data in the persistent store.


To copy a managed object from one context to another, you can use the object’s object ID, as illustrated in the following example.



NSManagedObjectID *objectID = [managedObject objectID];

NSManagedObject *copy = [context2 objectWithID:objectID];


let objectID = managedObject.objectID

let copy = context2.objectWithID(objectID)

I have a key whose value is dependent on values of attributes in a related entity—how do I ensure it is kept up to date as the attribute values are changed and as the relationship is manipulated?

我有一个键 它的值取决于一个有关的实体属性的值-如果去保证它是最新的随着属性值被改变和关系被操纵?

There are many situations in which the value of one property depends on that of one or more other attributes in another entity. If the value of one attribute changes, then the value of the derived property should also be flagged for change. How you ensure that key-value observing notifications are posted for these dependent properties depends on which version of OS X you’re using and the cardinality of the relationship.


OS X v10.5 and later for a to-one relationship

OS X 10.5和以后一个对一关系

If there is a to-one relationship to the related entity, then to trigger notifications automatically you should either override keyPathsForValuesAffectingValueForKey: or implement a suitable method that follows the pattern keyPathsForValuesAffectingValueForKey: defines for registering dependent keys.

For example, you could override keyPathsForValuesAffectingValueForKey: as shown in the following example:




+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key {

    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];

    if ([key isEqualToString:@"fullNameAndDepartment"]) {

        NSSet *affectingKeys = [NSSet setWithObjects:@"lastName", @"firstName",

                                                    @"department.deptName", nil];

        keyPaths = [keyPaths setByAddingObjectsFromSet:affectingKeys];


    return keyPaths;



class override func keyPathsForValuesAffectingValueForKey(key a href="" String /a ) ->  a href="" Set /a < a href="" String /a > {

    var keyPaths = super.keyPathsForValuesAffectingValueForKey(key)

    if key == "fullNameAndDepartment" {

        let affectingKeys a href="" Set /a  = ["lastName", "firstName", "department.deptName"]

        keyPaths = keyPaths.union(affectingKeys)


    return keyPaths


Or, to achieve the same result, you could just implement keyPathsForValuesAffectingFullNameAndDepartment, as shown in the following example:



+ (NSSet *)keyPathsForValuesAffectingFullNameAndDepartment {


    return [NSSet setWithObjects:@"lastName", @"firstName",

                                @"department.deptName", nil];



class func keyPathsForValuesAffectingFullNameAndDepartment() ->  a href="" Set /a < a href="" String /a > {

    return ["lastName", "firstName", "department.deptName"]


To-many relationships


The keyPathsForValuesAffectingValueForKey: method does not allow keypaths that include a to-many relationship. For example, suppose you have a Department entity with a to-many relationship (employees) to an Employee, and Employee has a salary attribute. You might want the Department entity to have a totalSalary attribute that is dependent upon the salaries of all the Employees in the relationship. You can not do this with, for example, keyPathsForValuesAffectingTotalSalary and returning employees.salary as a key.


There are two possible solutions:


Use key-value observing to register the parent (in this example, Department) as an observer of the relevant attribute of all the children (Employees in this example). You must add and remove the parent as an observer as child objects are added to and removed from the relationship (see Registering for Key-Value Observing). In the observeValueForKeyPath:ofObject:change:context: method you update the dependent value in response to changes, as illustrated in the following code fragment: 

使用键-值坚持去注册父类(在这个例子中,部门)作为一个所有子体(雇员在这个例子)相关属性的观测者。你必须添加或一场父类作为观测者随着子类被添加和移除从关系中(参见Registering for Key-Value Observing).在这个obserValueForKeyPath:ofObject:change:context:方法你更新到相应改变的独立值,就像代码中阐明的这样:


- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {


    if (context != totalSalaryContext) {

        return [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];


    if ([keyPath isEqualToString:@"totalSalary"]) {

        [self setTotalSalary:[self valueForKeyPath:@"employees.@sum.salary"]];


    // Deal with other observations and/or invoke super...



override func observeValueForKeyPath(keyPath a href="" String /a ?, ofObject object a href="" AnyObject /a ?, change: [ a href="" NSObject /a  a href="" AnyObject /a ]?, context a href="" UnsafeMutablePointer /a < a href="" Void /a >) {

    guard let keyPath = keyPath else {

        super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)



    switch (keyPath, context) {

    case("totalSalary", &totalSalaryContext):

        totalSalary = valueForKeyPath("employees.@sum.salary") as a href="" NSNumber /a 


        print("Unexpected key: \(keyPath)")



You can register the parent with the application's notification center as an observer of its managed object context. The parent should respond to relevant change notifications posted by the children in a manner similar to that for key-value observing.

你能使用应用的通知中心注册做为它的管理对象上下文的观察者。这个父类应该响应到相关被子类发送的改变通知 以一个和key-value观察相同的方式。

In Xcode’s predicate builder, why don’t I see any properties for a fetched property predicate?


If you want to create a predicate for a fetched property in the predicate builder in Xcode, but don’t see any properties, you probably have not set the destination entity for the fetched property.


How efficient is Core Data?


Throughout the development of Core Data, the engineering team compared the runtime performance of a generic Core Data application with that of a similar application developed without using Core Data. In general, the Core Data implementation performed better. There may nevertheless be opportunities for further optimization, and the team continues to pursue performance aggressively. For a discussion of how you can ensure you use Core Data as efficiently as possible, see Performance.



These questions are only relevant to using Core Data with OS X.


How do I get the GUI to validate the data entered by the user?

Core Data validates all managed objects when a managed object context is sent a save: message. In a Core Data document-based application, this message is sent when the user saves the document. To have the GUI validate the data as it is being entered, select the Validates Immediately option for a value binding in the Interface Builder Bindings inspector. If you establish the binding programmatically, you supply in the binding options dictionary a value of YES (as an NSNumber object) for the key a href="" NSValidatesImmediatelyBindingOption /a . See a href="" target="_self" Binding Options /a .

For details of how to write custom validation methods, see the subclassing notes for NSManagedObject.

When I remove objects from a detail table view managed by an array controller, why are they not removed from the object graph?

If an array controller manages the collection of objects at the destination of a relationship, then by default the remove method simply removes the current selection from the relationship. If you want removed objects to be deleted from the object graph, then you need to enable the Deletes Objects On Remove option for the contentSet binding in Interface Builder.

How do I get undo/redo for free in my nondocument app?

In a Core Data document-based application, the standard NSDocument undo manager is replaced by the undo manager of the document’s managed object context. In a nondocument application for OS X, your window’s delegate can supply the managed object context’s undo manager using the a href="" windowWillReturnUndoManager: /a delegate method. If your window delegate has an accessor method for the managed object context (as is the case if you use the Core Data Application template), your implementation of a href="" windowWillReturnUndoManager: /a might be as follows:


- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)sender {

    return [[self managedObjectContext] undoManager];



func windowWillReturnUndoManager(window a href="" NSWindow /a ) ->  a href="" NSUndoManager /a ? {

    return managedObjectContext!.undoManager


个人分类: API翻译
想对作者说点什么? 我来说一句