• CoreData简介

是Apple公司提供的本地化持久存储框架

    是对SQLite的对象化升级,将数据库转化为OC对象(托管对象),无需SQL知识也能使用

    将数据库中的每一行数据,转换为对象操作,这种对象被称作”实体"。

     

     CoreData位于MVC的Model层,是序列化存储和SQLite存储的折中方法,使用起来更加简单

     CoreData能将应用程序中的对象直接保存到数据库中,无需进行复杂的查询,也无需确保对象的属性名和数据库的字段名对应。

  • 模型文件

使用CoreData的第一步就是要创建模型文件,在模型文件中设计出要存储的模型

模型文件用于描述要本地化存储数据的模型,在Xcode中以.xcdatamodeld作为后缀

     Xcode中创建模型文件:new —> iOS —> CoreData —> Data Model

 添加实体:点击右下方的Add Entity 按钮,左侧列表显示所有的实体

     

实体 添加 属性:

     

实体 添加 关系:(复合关系)

     

  • CoreData中核心类及之间的关系

     

使用CoreData存储数据时,我们要使用的核心类是:上下文对象类NSManagedObjectContext

    NSManagedObjectContext是对模型对象数据存储的操作句柄

    其创建和使用离不开图中的其他几个类型:

    NSEntityDescription是模型文件文件中我们设计的一个模型

    NSManagedObjectModel描述的模型文件,其包含了我们设计的所有模型

    NSPersistentStoreCoordinator是协助器对象,通过这个对象关联上下文使用的存储

  • 配置模型上下文对象的过程

1)加载模型文件

NSManagedObjectModel 表示模型文件,包含多个表单或者集合

创建方法

+ (NSManagedObjectModel *)mergedModelFromBundles:(NSArray
 *)bundles

     bundles传nil则使用main bundle

     包含的所有的实体描述(NSEntityDescripiton)

@property(strong) NSArray 
 *entities

如:

//1.从程序包种加载模型文件NSManagedObjectModel * model = [NSManagedObjectModel mergedModelFromBundles:nil];

 

2)创建模型文件的协助器对象

     NSPersistentStoreCoordinator 协助器对象用于设定模型文件存储方式。

     通过指定NSManagedObjectModel创建

//2.初始化NSPersistentStoreCoordinator对象NSPersistentStoreCoordinator * psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];

 3)关联协助器对象使用的数据库

//3. 添加持久化的数据库NSError * err;NSURL * url = [NSURL URLWithString:[NSString stringWithFormat:@"file://%@/Documents/person.data", NSHomeDirectory()]];if ( ![psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:url options:nil error:&err] ) {    NSLog(@"%@", [err localizedDescription]);}

4)创建CoreData模型上下文对象

     NSManageObjectContext 类型是管理数据的上下文对象,负责与数据库之间的交互操作。

     即:模型的操作,需要在模型上下文中进行

     上下文对象的创建及协助器的关联:

//4. 创建上下文对象    _context = [[NSManagedObjectContext alloc] initWithConcurrencyType:0];_context.persistentStoreCoordinator = psc;

通过上面4步,就可以将CoreData的上下文对象配置完成,其中只有数据库的路径可能发生变化

  • 实体对象的创建及存储

准备工作完成后,接下来就是要使用对象,并将对象实时对应存储在CoreData中

NSEntityDescription类用于描述实体类型,其如下类方法用于创建实体对象

+ (__kindof NSManagedObject *)insertNewObjectForEntityForName:(NSString *)entityName inManagedObjectContext:(NSManagedObjectContext *)context

     参数entityName:为实体对象类型名,即在cdatamodeld文件中添加的实体类型名。

     参数context:为上下文对象

     返回值:实体对象NSManagedObject或其子类

     

创建的实体对象,需要上下文对象调用save方法进行保存

- (BOOL)save:(NSError * _Nullable *)error

上下文对象的其他操作:

- (void)deleteObject:(NSManagedObject *)object  //删除实体对象- (void)rollback  //回滚操作@property(nonatomic, readonly) BOOL hasChanges  //当前是否有更改未更新到数据库

  • 实体对象的使用:KVC

实体对象NSManagedObject,可以使用KVC进行属性操作

     如:实体对象创建后的赋值

NSManagedObject *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:self.context];[person setValue:name forKey:@"name"];[person setValue:@(age) forKey:@"age"];NSManagedObject *person = [NSEntityDescription insertNewObjectForEntityForName:@"Card" inManagedObjectContext:self.context];[card setValue:@"123456" forKey:@"no"];[person setValue:card forKey:@"card"];

     再如:输出实体对象的数值     

NSLog(@"name:%@ age:%@ no:%@", [obj valueForKey:@"name"], [obj valueForKey:@"age"], [obj valueForKeyPath:@"card.no"]);

  • 实体对象的使用:定义子类

上面的例子共创建了两种实体对象@“Person”和@“Card”,而对象指针类型都是NSManagedObject

从InsertNewObjectForEntityForName:方法的返回值类型可以看出一些端倪来  

(__kindof NSManagedObject *)

    __kindof 表示这个类型或这个类型的子类,也就是说我们应当去创建NSManagedObject的子类

使用NSManagedObject子类的好处:

    1)可以使用属性的方式代替KVC的方式

    2)可以为实体对象添加方法

创建NSManagedObject子类:

     new file -> iOS -> Core Data -> NSManagedObject subclass

     选择模型文件 -> 选择为那些实体创建子类

   

以Person实体类型简单解释一下:

    我们应当将额外需要添加的方法放在Person.h Person.m

    而Person+CoreDataProperties.h中是Person的一个分类,其中包含了在模型文件中设定的属性及关系

@interface Person (CoreDataProperties)@property (nullable, nonatomic, retain) NSNumber *age;@property (nullable, nonatomic, retain) NSString *name;@property (nullable, nonatomic, retain) Card *card;@end

    

  • CoreData中的数据查找

上下文对象使用其executeFetchRequest: error:方法进行数据库查询操作

- (NSArray *)executeFetchRequest:(NSFetchRequest *)request error:(NSError * _Nullable *)error

NSFetchRequest查询对象定义的查询的具体方式

创建(指定查询的实体)

 + (instancetype)fetchRequestWithEntityName:(NSString *)entityName

    参数entityName  查询的实体名

如:获得某一个实体类型的所有实体对象

NSFetchRequest * fr = [NSFetchRequest fetchRequestWithEntityName:@"Person"];NSArray *arr = [self.context executeFetchRequest:fr error:NULL];

查询对象的其他属性:

//查询的谓语:@property(nonatomic, strong) NSPredicate *predicate//查询结果数量限制:@property(nonatomic) NSUInteger fetchLimit//查询结果的偏移://@property(nonatomic) NSUInteger fetchOffset//查询的排序描述:@property(nonatomic, strong) NSArray 
 *sortDescriptors

  • NSPredicate谓词对象

NSPredicate谓词对象用于描述查询的限定条件

     类似于SQL语句的where语句

+ (NSPredicate *)predicateWithFormat:(NSString *)format, ...

     格式化字符串:

      age == 10      name == “aaa”      name like ‘’abc*”

     name like “abc*” OR age == 10

     group.name like “abc*”

     ALL children.age > 12

     ANY children.age > 12

如查询指定名字的Person实体对象

NSFetchRequest* fr = [NSFetchRequest fetchRequestWithEntityName:@"Person"];NSPredicate * predicate = [NSPredicate predicateWithFormat:@"name like %@", name];fr.predicate = predicate;NSArray * objs = [self.context executeFetchRequest:fr error:&err];

  • NSSortDescriptior排序描述对象

NSSortDescriptor用于描述一个排序

+ (instancetype)sortDescriptorWithKey:(NSString *)key ascending:(BOOL)ascending

     参数key:排序的字段

     参数ascending:是否按升序排序

还可以使用以下方法,自定义比较方式

+ (instancetype)sortDescriptorWithKey:(NSString *)key ascending:(BOOL)ascending comparator:(NSComparator)cmptr

     cmptr是一个block,用于实现比较操作

typedef NSComparisonResult (^NSComparator)(id obj1, id obj2);