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);