core data学习笔记


  1. 更新中
  2. 本文不是教程,只是学习笔记,内容杂乱无章仅仅是因为:manual就这样-。-!好像不同的章节外包给了不同的人。。
  3. 本文是学习中觉得比较重要的知识点的摘录,需要系统的学习请查看manual,需要速成教程本文的参考部分提供的几篇不错的文章。

一.入门(升职加薪)

  1. coreData实现什么样的目的:类似archiving实现对象的保存和恢复
  2. coreData相比archiving等有什么样的优势:
    • managing changes of your model objects==>支持redo undo;支持对象之间的关系管理.
    • 节约内存,取一部分对象subset
    • gui-based editor / setting of default values and attribute value validation
    • disjoint sets of edits of your objects.->不save 改变就是discard
    • easy upgrade/migration.
  3. 直接使用sqlite的不同
    • No primary keys means no foreign keys, either; Core Data manages the relationships between entities, or tables, and performs any necessary joins for you.
    • core data本身不是ORM,是object graph management framework,它可以选择sqlite,xml,plist或是其他方式作为持久化方案;不能读取任意的sqlite文件
    • 方便支持undo,redo
    • 你只需要worry about data,而不是data storage mechanisms.(举个例子many to many的关系会导致core data自动创建一个关系表,如果直接使用sqlte你需要自己考虑并创建)

!!!注意:尽管不需要考虑存储机制,但是data model的设计还是需要深思熟虑的.Relational Database Normalization的规则在设计datamodel的时候同样需要被考虑。一个简单的数据库标准化的参考

1. 几个重要的概念/class

1.1 Managed Object Model:

You can think of this as the database schema. It is a class that contains definitions for each of the objects (also called “Entities”) that you are storing in the database是描述应用程序的数据模型,这个模型包含实体(Entity),特性(Property),读取请求(Fetch Request)等. Usually, you will use the visual editor you just peeked at to set up what objects are in the database, what their attributes, and how they relate to each other. However, you can do this with code too!

1.2 Persistent Store Coordinator:

You can think of this as the database connection. Here’s where you set up the actual names and locations of what databases will be used to store the objects, and any time a managed object context needs to save something it goes through this single coordinator,处理底层的对数据文件的读取与写入。一般我们无需与它打交道.

1.3 Managed Object Context:

You can think of this as a “scratch pad”(object space) for objects that come from the database. It’s also the most important of the three for us, because we’ll be working with this the most. Basically, whenever you need to get objects, insert objects, or delete objects, you call methods on the managed object context (or at least most of the time!);Managed Object Context是Managed Object和其他CoreData模块的桥梁因此你应该总希望keep reference to it.

1.4 Managed Object

代表一个Entity的类;

1.5 Entity Description

注意理解这样的概念Entity是数据,但是它同时又是一个抽象的概念,他必须有实体的类来描述和代表他.一个Entity Description就是用来描述这个Entity的,描述的目的可能是为了对Entity进行fetch等相关操作等;而Entity取出来了之后又需要一个实体类来代表它,这个类就是一个managed object类.

//Managed Object Model--包含-》Entity Description<---Entity--->managed object;//见图1.2,1.3.managed object和Entity Description

//你可以从datamodel获取Entity Description
NSEntityDescription *employeeEntity = [[managedObjectModel entitiesByName] objectForKey:@"Employee"];

//也可以从context直接获取
NSEntityDescription *employeeEntity = [NSEntityDescription entityForName:@"Employee" inManagedObjectContext:context];

// Entity Description 和managed object是彼此关联的 可以通过Entity Description得到managed object// 也可以

img

Figure 1-1 A simple Core Data stack—1

img

Figure 1-2 A simple Core Data stack-2

img

Figure 1-3 Managed objects in a context, and a table in the persistent store

2. 定义数据:Data model=》Managed Objects

2.1. (Subclass of)NSManagedObject 可以看成是数据表的一个record。a record in a table in a database.

img

2.2. NSManagedObjectModel和 NSManagedObject的关系:model是描述数据模型的schema,是一组entity description objects (instances of NSEntityDescription)的集合; 一个entity description描述一个entity (a table in a database).

当datamodel变化的时候core data不能读取数据->类似的存储方式都有类似问题,coredata提供了管理这种变化的方法--Core Data Model Versioning and Data Migration Programming Guide

img

Figure 2-1 illustrates the relationship between an entity description in a model, a table in the database, and a managed object corresponding to a single record in the table.

2.3. With Core data you cannot retrieve only certain attributes of an object – you have to retrieve the entire object. 也就是说不能像数据库一样只拿出一项中的部分列出来,如果要实现这样的功能需要 factor the objects into serverral pieces 把对象分成几部分.
2.4. Auto Generating Model Files:自动生成数据object的oc文件(也可以不使用 用setvalueforkey解决)

使用自动生成的subclass of NSManagedObject有什么好处:

  1. Better support from the development tools.(You get code completion for property accessor methods, and compile-time type- and symbol-checking;这就是为什么在自动生成的class里头属性都声明为dynamic,coredate自动runtime生成accessor;同时也没有delloc因为生命周期由coredata管理--自己新建要自己管理)
  2. Support for custom methods for the entity.(In many situations, you want to provide special logic for the entity, such as validation methods or derived properties)
    生成完成之后你会发现datamodel里的entity class也被自动更新了.
2.5.Managed Objects / Entity 的一些属性
  • NSEntityDescription:是一个Entity的描述,而Entity是一个抽象的概念,并没有Entity这样一个类,Entity代表了数据,可以继承Entity,使用abstract entity;Entity是与NSManagedObject这个class对应的(但是并不完全等同),一个Entity由NSManagedObject代表;而一个Entity的instance由一个NSManagedObject的实例代表,实际理解中可以把Entity等同于代表其的NSManagedObject class。Abstract Entities - you will not create any instances of that entity.
  • NSEntityDescription 有属性 NSAttributeDescription 和 NSRelationshipDescription,NSFetchedPropertyDescription 用于描述Entity在schema中的特点.
  • Properties:对象的属性,包括Attribute,Relationship,Fetched Property
  • Attribute可以是transient说明实际不会被保存,一般是runtime的时候生成的.Index/optional类似数据库中的概念类似.可以设置类型和validation。但是不建议设置optinal,尤其是数值类型的,尽量不设置optinal并设置default value因为数据库中的NULL不同于0或者@"" (数据库中的NULL取出来对应nil并没有问题,predicate也可以设置nil,但是nil = 0这样会造成混淆--nil=NULL=Nil=0,[NSNull null]!=0);另:保存为transformable是用二进制/nsdata/BLOB来保存数据,通常来说不是一个好的选择,和binary data类型区别仅仅是多了一个转换过程(比如nscolor可以转成字符串或16进制数而不是nsdata,二进制不易于查询)
  • fetch property:Relationship 在对象中变成对应关系的指针,使用时load对应的数据.Fetched properties represent weak, one-way relationships.
  • Fetch Request Templates:是常用的Fetch Request,用的时候从datamodel获取即可直接使用 managedObjectModel.fetchRequestTemplatesByName[@"FetchRequestName"]
  • User Info Dictionaries:和datamode绑定的其他任意信息.
  • Configurations:一般用于多个数据store(详解见第二部分)。
Managed Object Model 抽象 NSManagedObjectModel 数据模型
Entity NSEntityDescription 抽象数据类型,相当于数据库中的表
Property NSPropertyDescription Entity 特性,相当于数据库表中的一列
> Attribute NSAttributeDescription 基本数值型属性(如Int16,BOOL,Date等类型的属性)非标准Transformable...
> Relationship NSRelationshipDescription 属性之间的关系
> Fetched Property NSFetchedPropertyDescription 查询属性(类似一种单向关系,易用查询)

img

img

Figure 2-2 Entity description with two attributes and a relationship

3.操作数据:添加、fetch、删除Managed Objects.

3.1 添加:insertNewObjectForEntityForName:inManagedObjectContext: 获得对应的ManagedObject-》修改属性 (-》save)
3.2 Fetch:需要一个fetch request,设置其NSEntityDescription,predicate,sort descriptor=》类似一个select语句(Open the Scheme drop-down in Xcode and select ‘Edit Scheme…’. Select the ‘Run’ scheme and select the ‘Arguments’ tab. Add the following argument: “-com.apple.CoreData.SQLDebug 1”.这样可以让你看到原始的select语句)
  • NSFetchedResultsController用于为tableviewfetch数据,经过了优化可以节约大量代码以及保证效率和内存上的优化.
  • You cannot fetch using a predicate based on transient properties
  • 可以fetch特定的object用来检查是不是被删掉了 感觉使用场景不是很高[NSPredicate predicateWithFormat:@"self == %@", targetObject];也可以使用@"self IN %@",arrayOfManagedObjectIDs
  • 如果要fetch一个特定的比如value是最大值的可以使用 NSExpression(详见programing guide)
  • fetch 设置成 super-entity 的时候会得到满足要求的所有sub-entities和super-entity(如果不是abstract的)
3.3 删除: managedObjectContext deleteObject: (-》save)(删除的时候需要考虑relationship不同的relationship删除策略不一样)
  • 删除会发送 NSManagedObjectContextObjectsDidChangeNotification

img

3.4 操作关系属性:得到关系属性的时候获得的是一个fault object
  • 一对一关系:
  • 一(多)对多关系:
  • 一个隐含的知识点:当你取得一个关系的object的时候没有必要设置一个fetch,会自动帮你取得(开始是个fault)
// 使用KVC
NSMutableSet *employees = [aDepartment mutableSetValueForKey:@"employees"];
[employees addObject:newEmployee];
[employees removeObject:firedEmployee];


// or 使用自动生成的关系操作方法
[aDepartment addEmployeesObject:newEmployee];
[aDepartment removeEmployeesObject:firedEmployee];

//1.是.employees返回的是set 和 mutableSetValueForKey 返回的有所不同 操作这个set
// KVO change notifications are not emitted and the inverse relationship is not updated correctly.
[aDepartment.employees addObject:newEmployee]; // do not do this!

值得注意的是:无论是添加 还是 删除 对managedObjectContext 操作的同时还需要对你用于缓存的datasource进行同样的操作.managedObjectContext 会缓存object 必要的时候 可以 managedObjectContext refreshObject:mergeChanges/reset可以清空缓存以节约内存,同时可用[[context registeredObjects] count]查看.

img

Figure 3-1 fetch request 示意

img

Figure 3-2 fetch 流程

img

二.理解(迎娶白富美)

1.理解 Managed Object Model

1.1 创建Managed Object Model:可以使用xib或者完全使用code
1.2 Compiling Model:xcdatamodeld是 deployment resource 经过特殊的编译器 momc 编译 成为 mom文件(momd是文件夹)
1.3 Loading Model:两种方法initWithContentsOfURL (指定url,preferred)/ mergedModelFromBundles (如果不需要分开model的时候)
1.4 Change Model:如果还需要访问existing stores中的数据就不能直接修改Model,而是应该 have a versioned model;修改时创建一个新的version model旧的不动
1.5 Localizing Model:providing localizationDictionary

img

img

2.理解 Managed Object

2.1 概念:Managed Object是NSManagedObject的instance / associated with an entity description (an instance of NSEntityDescription)/ associated with a managed object context /record 和 object是一对多的关系,因为可能有几个context等情况,几个object可能对应的是同一个数据
2.2 Object Accessor:
  • 自动生成Accessor(注:如果你自己写Accessor, dynamically-generated method snever replace your own code.);
  • 基于KVO;
  • 没有执行NSCopying协议
  • weak会被当成strong,只能用strong和copy
  • To Many Relation会变成NSSet;同样自动生成catgory方法;
  • dynamic的方法子类不能super
  • 如果要自定义accessor方法需要符合特定的规则:按照顺序调用relevant access and KVO change notification methods(Important: You are strongly encouraged to use dynamic properties)见下面的代码示例.
2.3 Managed Object 和其他对象有三点主要不同:
  • instance of (subclass of) NSManagedObject
  • Exists in an environment defined by its managed object context
  • Has an associated entity description that describes the properties of the object
  • (核心元素是一个context一个entity description)
  • (创建不用alloc;初始化不重载init见3.1)
 @interface Department (PrimitiveAccessors)
  - (NSString *)primitiveName;
  - (void)setPrimitiveName:(NSString *)newName;
  @end


- (NSString *)name
{
      [self willAccessValueForKey:@"name"];
      NSString *myName = [self primitiveName];
      [self didAccessValueForKey:@"name"];
      return myName;
}
- (void)setName:(NSString *)newName
{
      [self willChangeValueForKey:@"name"];
      [self setPrimitiveName:newName];
      [self didChangeValueForKey:@"name"];
}


//类似的当你想实现一个scalar type (NSInteger or CGFloat), or one supported by NSKeyValueCoding (NSRect, NSPoint, NSSize, NSRange),

@property CGFloat radius;

- (CGFloat)radius
  {
      [self willAccessValueForKey:@"radius"];
      float f = _radius;//数据库取出存在_radius => 转换成 float
      [self didAccessValueForKey:@"radius"];
      return f;
}

3.操作 Managed Object(2.3续)

3.1 Managed Object IDs and URIs

A managed object ID uniquely identifies the same managed object both between managed object contexts in a single application, and in multiple applications (as in distributed systems);创建的时候是temporary的可以用isTemporaryID测试.类似表里的primary key但是范围更大.可以转换成url的形式URIRepresentation通过他们可以直接获取对应的object;甚至可以在不同的store里传递

3.2 Validation

需要指出的是,KVC是不会自动调用键值验证方法的,就是说我们需要手动验证。但是有些技术,比如CoreData会自动调用

  1. Property-Level Validation:下面的第一个方法
  2. Inter-Property validation: 下面的第2-4个方法;提供了更多validation;和Property-Level Validation不同的是,validation的关注点在于不同的combination是不是符合要求;注意要类似[super validateForInsert:error]先运行父类的方法to ensure that individual property validation methods are also invoked
//如下的4个方法在Managed Object的生命周期会自动触发 // validateValue 会自动调用- (BOOL)validate<Key>:error: (可以重载他而不要直接重载validateValue)
- (BOOL)validateValue:(id *)value forKey:(NSString *)key error:(NSError **)error;    // KVC

// 下面三个是Inter-Property validation 提供了更多的validate的机会
- (BOOL)validateForDelete:(NSError **)error;
- (BOOL)validateForInsert:(NSError **)error;
- (BOOL)validateForUpdate:(NSError **)error;
// 要注意的一个问题是:对于error的处理,error可能是已经存在的,这时候需要添加error信息而不是重新赋值//be sure to combine errors and not overwrite them
3.3 Faults

In some situations a managed object may be a “fault”—an object whose property values have not yet been loaded from the external store. When you access persistent property values, a fault “fires” and its persistent data is retrieved automatically from the store.可以手动把一个方法变成fault:NSManagedObjectContext's refreshObject:mergeChanges:.比方说object的一个关系属性在没使用的时候就是一个fault。

3.4 Ensuring Data Is Up-to-Date

refreshObject:mergeChanges:根据mergeChanges的flag操作是merge还是变成fault;注意transient的属性刷新之后会变成pre-refresh value after awakeFromFetch is invoked;为了保证transient的属性是最新的可以设置**IsValiddid属性并在TurnIntoFault方法里写成NO

3.5 不同context copy and paste
NSManagedObjectID *objectID = [managedObject objectID];
NSManagedObject *copy = [context2 objectWithID:objectID];

4.Object内存管理:

4.1 Managed Object和Context
  • 两者是关联的,但是关系是weak的。不过context在其中的Managed Object的pending transaction/reset/rollback之前是有strong reference的(undomanager在之后都有strong reference);
  • 设置setRetainsRegisteredObjects可以是使得Managed Object依赖与context(但是一般不会这么做,因为你自己可以设置一个NSArray之类的集合来管理你的数据的生命周期)
  • 使用上面讲过的refreshObject:mergeChanges也可以用来打破object之间的retain cycle
4.2 Object Life-Cycle
  • init:three different ways you can customize initialization —by overriding initWithEntity: insertIntoManagedObjectContext:, awakeFromInsert, or awakeFromFetch 不要override init ;推荐使用awakeFromInsert, or awakeFromFetch分别在insetNew和fetch方法之后被执行
  • validate:not override validateValue:forKey:error: ; override validate<Key>:error:. If you want to validate inter-property values, you can override validateForUpdate: and/or related validation methods; validateValue:forKey:error: 内部会自动调用 validate<Key>:error:
  • delloc:不要重载delloc;core data负责释放资源,释放之前调用didTurnIntoFault;可以重载didTurnIntoFault
  • fault:an object whose property values have not yet been loaded from the external data store
    1.你的datasource何时被释放
    2.context的cache何时释放
4.3 Faulting and Uniquing
  1. A fault is a placeholder object that represents 1)a managed object that has not yet been fully realized, or 2)a collection object that represents a relationship.
  2. fault的使用相当于lazy loading除非使用否则不需要真正的fetch,这样就减少了内存使用.fetch的动作叫做fire the fault.如果是fault那么可能是下面说的情况2)在缓存中,3)不在缓存中,需要fetch 可以用isFault测试,如果是NO那么肯定是情况1)
    • 1)对象已经在 context 中,这种操作基本上是没有任何代价的。
    • 2)对象不在 context 中,但是因为你最近从 store 中取出过对象,所以持久化存储协调器缓存了对象的值。这个操作还算廉价(但是,一些操作会被锁住)。操作耗费最昂贵的情况是
    • 3)当 context 和持久化存储协调器都是第一次访问这个对象,这种情况必须通过 store 从 SQLite 数据库取回。
    • 注意区别fault和cache的区别,变成fault还是占内存的,只是变成一个类似指针的占位符,然后fault
      之后可能会释放所有对它的reference,这时会将其清除出cache,不占任何内存;(分别用refeash和reset强制控制)。
  3. refreshObject:mergeChanges:可以手动把一个object变成fault=>会发出 didTurnIntoFault 的message;可以重载做"housekeeping"类的一些操作; key-value observing (KVO) change notifications也会被sent
  4. Uniquing是保证an entry in a persistent store is associated with only one managed object的技术

5.Relationship And fetch properties

5.1 Relationship定义
  • Relationship可以同时是optional的又设置上下限,意思是可以不存在,但是如果存在那么就要满足上下限要求
  • Relationship Delete Rules:Deny;Nullify;Cascade;No Action几种rule觉得delete对象时的操作(很好理解详见programming guide -p84)。当你移动,删除一个带有关系的object的时候,coredata 会自动为你检查规则和更新关系.
  • programming guide -p84有一个many to many的例子,大多时候数据库效率不高或者难于使用并不是framework的问题,而是设计不合理。
  • Relationship一般都是双向的,创建一个单向的relationship基本没什么好处.
5.2 Fetched Properties
  • Fetched properties represent weak, one-way relationships但是不同的是fetch语句实现的,因此是array,evaluated lazily;
  • Fetched properties和fetch request template都是fetch语句,不同的是Fetched properties会cache fetch的object(这里要注意keep data up-to-date);同时Fetched properties一般用在fetch 不同的table之间的元素;fetch request template;fetch的是一个table里的元素 两者都可以在代码里通过一个fetch语句实现
5.3 例子 获得一组数据中创建日期最早的那个的日期
  • 方法1:fetch所有的排序,取第一个;===>设置fetch limit只取一个
  • 方法2:fetch所有的排序,取第一个;和1不同的是只fetch日期这个字段
[fetchRequest setResultType:NSDictionaryResultType]; 
[fetchRequest setPropertiesToFetch:[NSArray arrayWithObject:@"createdAt"]];
  • 方法3:使用Expression效率最高NSExpression==》NSExpressionDescription=》setPropertiesToFetch

    6. Using Persistent Stores

    6.1 创建一个store:NSPersistentStore
    ```
    //使用这个函数会创建一个NSPersistentStore代表了你的存储文件,一个隐含的操作是,如果存储文件不存在,就会先创建它
    NSPersistentStoreCoordinator psc = [moc persistentStoreCoordinator];
    NSPersistentStore 
    roStore = [psc addPersistentStoreWithType:NSXMLStoreType
                              configuration:nil URL:url options:options error:&error];
    

//你不会直接使用NSPersistentStore;而是应该通过NSPersistentStoreCoordinator

#####6.2 Changing a Store’s Type and Location

NSPersistentStoreCoordinator psc = [aManagedObjectContext
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
toURL:newURL options:nil withType:NSSQLiteStoreType error:&error];


#####6.3 Associate Metadata With a Store
- get: metadataForPersistentStore:/ metadataForPersistentStoreOfType:URL:error:.
- set: setMetadata:forPersistentStore:/setMetadata:forPersistentStoreOfType:URL:error:.
- use: 一个使用场景是migration=>使用系统自动创建的metadata就可以了isConfiguration:compatibleWithStoreMetadata;metadata不同(如版本)就会返回NO


##7.How To Preload and Import Existing Data
两种解决方案

1. `Fill in Core Data on startup from external source`. For this the app can start up, notice that the database hasn’t been imported yet, and start reading in data from an external source (such as an SQLite database or XML file) and then start inserting the data into Core Data.

2. `Provide pre-filled in SQLite database`. For this we’ll let Core Data create the database structure for us based on the model, and then we populate the database with a utility app. The utility app could be a Mac or iPhone app that uses Core Data to populate the database via Core Data APIs, or some kind of program that fills in the SQLite database directly. Once the database is populated, just include it with the app and make the app use it as the default database if no database already exists. 就是代码里先生成sqlite文件,加入bundle,初始化的时候 copyItemAtURL 复制到本地目录.这是苹果文档官方推荐的方法,但是考虑到先创建数据库文件可能使得文件比较大,这个需要权衡.


##8.Fetched Results Controller<=>UITableView
#####8.1 简介
1. ee
2. 组成
    - A fetch request (NSFetchRequest instance):The one difference in this fetch request is that it must have at least one sort descriptor
    - A managed object context
    - A section name key path:用于coredata自动根据keypathname分割成几个section
    - A cache name


#三.深入(走上人生巅峰)
##1.Migrations
#####1.1 Lightweight Migrations
一类比较小的迁移,不需要创建mapping model;coredata会自动使用sql语句进行迁移,不需要load data或者转移整个store所以效率一般很高.(迁移之后iOS 5 keeps only the post-migration version)

//1.1
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, //tells the persistent store coordinator to automatically migrate the data.
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];//tells the persistent store coordinator to infer 推断 the mapping model.

//对于1,2 设置 NSInferMappingModelAutomaticallyOption为NO!!!


![img](http://t2.qpic.cn/mblogpic/f29ec105d4105dc88f20/2000)
![img](http://t2.qpic.cn/mblogpic/6b88c7ee99f6ea419df4/2000)
![img](http://t2.qpic.cn/mblogpic/6dd96b53f2463b80f62a/2000)

#####1.2 Migrate With Mapping Model
当改变不限于1.1所述的轻度迁移的时候,需要创建mappging model-》tell Core Data how to execute the migration

- NSAddEntityMappingType;NSRemoveEntityMappingType;NSCopyEntityMappingType lightweight migrations就可以处理
- NSTransformEntityMappingType可以用 value expression 来描述
- NSCustomEntityMappingType 则需要创建一个 NSEntityMigrationPolicy 的子类来描述;

处理步骤

![img](http://t2.qpic.cn/mblogpic/06d636d566c04f1c8be6/2000)

//Core Data runs your migration in three stages.这个步骤细节可以由NSEntityMigrationPolicy来描述

  1. It creates the objects in the destination model, including their attributes, based on the objects in the source model. ==>createDestinationInstancesForSourceInstance
  2. It creates the relationships among the objects in the destination model.=>createRelationshipsForDestinationInstance
  3. It validates the data in the destination model and saves it.=>performCustomValidationForEntityMapping

//2 example use expression: FUNCTION(manager,"destinationInstancesForEntityMappingNamed:sourceInstances:","CanvasToCanvas",source.canvases)
//caveat:createDestinationInstancesForSourceInstance的时候如果不super那么需要associateSourceInstance: withDestinationInstance: forEntityMapping:

#####1.3 渐进式迁移 (Progressive Migrations)http://objccn.io/issue-4-7/


##2. Multiple context#####2.1 如何处理冲突1. Conflict Detection and Optimistic Locking:Optimistic Locking的原理When Core Data fetches an object from a persistent store, it takes a snapshot of its state,保存的时候要比较这个数据库里的对象和它的snapshot,如果不同说明这个对象在fetch之后被别人改过了=>Optimistic Locking(snapshot也会占用内存,它通过叫snapshot reference counting的机制管理)
2. 如何处理冲突由NSErrorMergePolicy(默认)/NSMergeByPropertyStoreTrumpMergePolicy/NSMergeByPropertyObjectTrumpMergePolicy/NSOverwriteMergePolicy指定
3. Communicating Changes Between Contexts: NSManagedObjectContextDidSave

##3. Concurrency with Core Data
> For the most part, AppKit and UIKit are not thread safe; in particular, on OS X Cocoa bindings and controllers are not thread safe—if you are using these technologies, multi-threading may be complex.


#####3.1 typically-recommended approach
- Create a separate managed object context for each thread and share a single persistent store coordinator.不应该在不同thread传递Managed Object;如果要访问同一个entity,可以使用objectID或者构建同样的fetch;
- 一般没有必要给Managed Object或者contexts lock(programming guide p137描述了需要lock the persistent store coordinator的情况)

#####3.2 Track Changes in Other Threads Using Notifications
- 没错,Notifications..需要注意的是哪个线程post的Notifications那个线程才能收到,因此你需要在你save的contex所在的线程使用,比如使用performselector [mergeChangesFromContextDidSaveNotification] on Thread(你想通知的context所在的线程) 
- 你希望收到通知的线程注册NSManagedObjectContextDidSaveNotification;(再把他作为参数发给mergeChangesFromContextDidSaveNotification.这样 the context is able to safely merge the changes.);由于不同object和不同context关联,所以不改直接传递。可以传递objectid
- Fetch in the Background for UI Responsiveness;`fetch操作是经过内部优化的,如果需要coredata会自己新建线程来加快操作`.但是如果还是需要在子线程fetch来防止UI阻塞,你可以新建background thread 以及对应的context,在其中fetch然后传递object ID;另一个线程通过object ID获取已经cache了object
- 在后台线程保存:If you need to save on a background thread, you must write additional code such that the main thread prevents the application from quitting until all the save operation is complete.

注意点
1.Use one NSPersistentStoreCoordinator per program. You don't need them per thread.
2.Create one NSManagedObjectContext per thread.
3.Never pass an NSManagedObject on a thread to the other thread.
4.Instead, get the object IDs via -objectID and pass it to the other thread.
More rules:

5.Make sure you save the object into the store before getting the object ID. Until saved, they're temporary, .and you can't access them from another thread.
6.And beware of the merge policies if you make changes to the managed objects from more than one thread.
7.NSManagedObjectContext's -mergeChangesFromContextDidSaveNotification: is helpful.

##4.Core Data Performance 提高效率的一些提示

1. Predicates的使用有技巧:一个例子 (salary > 5000000) AND (lastName LIKE 'Quincey') 比 (lastName LIKE 'Quincey') AND (salary > 5000000) 好;`巧用subquery能极大的提高fetch效率`2. fetchLimit:如果数据很多需要设置它,一次拉一部分数据;fetch某个需要的属性其他不要。
3. 不要fire 一个 fault的时候,不要fire
4. Batch Faulting and Pre-fetching with the SQLite Store:有些情况下一个个的fire fault反而效率很低,这时候可以`batch fault`(fetch request using a predicate with an IN operator或者use the NSFetchRequest method setReturnsObjectsAsFaults)`Pre-fetching`use the NSFetchRequest method setRelationshipKeyPathsForPrefetching)【p145】
5. 节约内存
    - re-fault an individual managed object using NSManagedObjectContext’s refreshObject:mergeChanges: method
    - create a fetch request you can set includesPropertyValues to NO 当你确定不需要使用这个property的时候
    - reset method of NSManagedObjectContext to remove all managed objects associated with a context
    - If you iterate over a lot of objects, you may need to use local autorelease pool block
    - 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. 
    - break cycles by re-faulting objects (again by using the refreshObject:mergeChanges

6. `使用instrument中的coredata工具`

//不会fire fault的方法
isEqual:, hash, superclass, class, self, zone, isProxy, isKindOfClass:, isMemberOfClass:, conformsToProtocol:, respondsToSelector:, description, managedObjectContext, entity, objectID, isInserted, isUpdated, isDeleted, and isFault.

##5.Multiple Persistent Store & Custom Persistent Store - Multiple Persistent Store可以使用configuration进行配置,这样可以split data 到不同的data store;[persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:@"Passwords" URL:passwordStoreURL options:nil error:&error]
- coredata允许创建custom的存储方式,但是这种方式只能是atomic store types(An atomic store is a store that writes its entire content all at once every time a save operation is executed).比如可以创建类似CSV file的保存格式. 
- 需继承NSAtomicStore:在NSAtomicStore重载load和save等方法.比方说对于一个CSV文件,就是对文本的解析和保存,类似json的解析和序列化.而使用NSAtomicStore的好处是底层保存格式发生改变的时候上层代码不需要改变.

![img](http://t2.qpic.cn/mblogpic/167f3f073de749b3fd38/2000)


##6.补充NSPredicate和NSExpression入门

![img](http://t2.qpic.cn/mblogpic/ae1ca50bc0722d69ea04/2000)

#####6.1 NSExpression是NSPredicate的内部实现方式`NSPredicate是非常有用的,是Cocoa的优势之一。``处理数据`的时候要善于使用NSPredicate可以使代码清楚简介。(比如当你在filter一个array的时候不要再使用遍历了)

//用NSExpression实现
NSExpression exprName = [NSExpression expressionForKeyPath:@"name"];
NSExpression
exprJ = [NSExpression expressionForConstantValue:@"J"];
NSPredicate p1 = [NSComparisonPredicate predicateWithLeftExpression:exprName rightExpression:exprJ modifier:NSDirectPredicateModifier type:NSBeginsWithPredicateOperatorType options:0];
NSExpression
exprAge = [NSExpression expressionForKeyPath:@"age"];
NSExpression lower = [NSExpression expressionForConstantValue:[NSNumber numberWithInt:20]];
NSExpression
upper = [NSExpression expressionForConstantValue:[NSNumber numberWithInt:35]];
NSExpression exprRange = [NSExpression expressionForAggregate:[NSArray arrayWithObjects:lower, upper, nil]];
NSPredicate
p2 = [NSComparisonPredicate predicateWithLeftExpression:exprAge rightExpression:exprRange modifier:NSDirectPredicateModifier type:NSBetweenPredicateOperatorType options:0];
NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:p1, p2, nil]];

//改写成NSPredicate+query language
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name BEGINSWITH %@ AND age BETWEEN {%d, %d}", @"J", 20, 35];
```

6.2 NSPredicate相关

img

img

img

img

img

img

img

参考

注意:部分资料比较陈旧,请查看最新版

  1. coredata 学习指南
  2. Core Data Tutorial for iOS
  3. Core Data Utility Tutorial
  4. Core Data Programming Guide
  5. Predicate Programming Guide
  6. Core Data Snippets
  7. Core Data Model Versioning and Data Migration Programming Guide
  8. Atomic Store Programming Topics
  9. Incremental Store Programming Guide
  10. Avoiding Ten Big Mistakes iOS Developers Make with Core Data
  11. 深入浅出 Cocoa 之 Core Data
  12. objccn.io有8篇翻译的coredata介绍的文章
  13. Core Data Queries Using Expressions
  14. How To Work with Relations and Predicates
  15. CoreData并发处理
  16. Pro Core Data for iOS【Data Access and Persistence Engine for iPhone, iPad, and iPod touch
    Second Edition】
  17. NSPredicate
资源
  1. sqlitebrowser
更新
  1. 2014-8-3第一版
  2. 2 2014-8-11增加了来自Pro Core Data for iOS的内容
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值