iOS CoreData 介绍和使用(以及一些注意事项)
iOS CoreData介绍和使用(以及一些注意事项)
最近花了一点时间整理了一下CoreData,对于经常使用SQLite的我来说,用这个真的有点用不惯,个人觉得实在是没发现什么亮点,不喜勿喷啊。不过这门技术的出现也有其存在价值,这是不可否认的事实,即使是不喜欢我们也得去了解一下,因为你不用别人会用,这年头都多人开发,多学点还是有好处的。废话不多说了,该开始正经事了。
CoreData介绍
CoreData是一个模型层的技术,也是一种持久化技术(数据库),它能将模型对象的状态持久化到磁盘里,我们不需要使用SQL语句就能对它进行操作。不过在性能方面是弱于直接使用SQLite的。
CoreData使用
理论我就不多说了,觉得我说的不够详细的可以自行搜索关于更多的CoreData介绍。
- 创建步骤流程
- 第一步先创建.xcdatamodeld文件(New File -> iOS -> Core Data ->Data Model)
 
 
名字虽然可以任意取,但最好还是取和自己存储数据库名字一样的名字。这样可读性更高些。(ps:这个文件就相当于数据库文件一样,数据库文件中可以有多个表,表中可以有各个字段值,这里也可以有多个实体,每个实体有各个键值)
 
通过上面的操作就可以创建一个.xcdatamodeld文件,现在我们点击这个文件,在最下面找到Add Entity按钮,进行实体添加。
 
现在我们添加了一个名字为Entity的实体,这个名字是默认名字,现在我们可以对他进行名字的更改,对它双击一下即可修改名字,或者在xcode右边的信息栏中也可以修改
 
通过上面操作我们已经创建好了实体的名字,现在我们需要往实体中添加我们需要的键值。(ps:相当于数据库表中的字段),具体操作看图说话(实体之间的关联我就不介绍了,有兴趣的可以自行搜索资料,个人觉得会了单个实体创建外加查询就行,关联也无非是找到关联的实体中共同的键值从而取得另外一个实体对象,我们可以直接先从一个实体取得指定键值对应的属性,再通过属性值去查询另一个实体,只是没关联的那么方便而已)。
 
- 第二步创建关联类来操控CoreData实体对象(选中.xcdatamodeld文件->xcode菜单栏->Edit->Create NSManagedObject Subclass)
 
选中自己需要关联的.xcdatamodeld文件名称,点击下一步即可。
 
选中.xcdatamodeld文件中需要关联的实体对象,点击下一步然后在选择存储目录即可。
 
完成后会发现自动生成了实体名称对应的类和扩展类(Entity.h/.m和Entity+CoreDataProperties.h/.m)
 
到这里就完成了整一个创建的流程,个人觉得说的有点过于详细了(导致看起来有点啰嗦)
- 注意
我在试验的过程中发现,如果我把关联的类从项目中删除,在对实体名称再次修改后,重新创建关联类,发现类名还是原来的实体名称显示,可能xcode没刷新,反正最后我是删除实体重新Add
Entity之后才有用,所以为了不必要麻烦,最好还是想好实体名称后再创建关联类。
- 关联类的理解 - 我就以我自己创建的类来说明 - #import "UploadEntity.h" NS_ASSUME_NONNULL_BEGIN @interface UploadEntity (CoreDataProperties) @property (nullable, nonatomic, retain) NSString *fileName;
 @property (nullable, nonatomic, retain) NSString *fileSize;
 @property (nullable, nonatomic, retain) NSNumber *fileType;
 @property (nullable, nonatomic, retain) NSNumber *finishStatus;
 @property (nullable, nonatomic, retain) NSData *imageData;
 @property (nullable, nonatomic, retain) NSNumber *time;
 @property (nullable, nonatomic, retain) NSString *urlPath; @end NS_ASSUME_NONNULL_END- 该类继承NSManagedObject类 
- 可以看到在实体中的每一个键值都被xcode自动生成了实体类的对象属性,而且对于基本数据类型被自动转成了NSNumber。 
- 每个对象的修饰词都有nullable,表示CoreData数据库存储的对象可能为nil(允许存储nil,就如数据库一样,字段值也能为NULL),也就是说我们以后从CoreData读取的数据是有可能为nil。 
- 这个类对象的创建我们不能用以往的[[NSObject alloc] init]方式去创建,因为经过验证直接这样创建它,然后对属性赋值会直接抛出异常,估计内部经行了断言操作吧。苹果API提供了几个专门创建实体对象的方法,后面我在讲。 
- 因为各种限制的原因,比如创建对象限制等,导致了我不好去封装,最后不得已想到个折中办法(下面会讲)。基本这一轮下来我的兴趣缺失了很多。 
 
- CoreData API介绍 - NSManagedObjectContext - 这个对象有点像SQLite对象(个人理解:用来管理.xcdatamodeld中的数据)。
 负责数据和应用库之间的交互(CRUD,即增删改查、保存等接口都是用这个对象调用).
 每个 NSManagedObjectContext 和其他 NSManagedObjectContext 都是完全独立的。
 所有的NSManagedObject(个人理解:实体数据)都存在于NSManagedObjectContext中。
 每个NSManagedObjectContext都知道自己管理着哪些NSManagedObject(个人理解:实体数据)
 // 创建方式(一般这个对象最好声明成成员变量)
 self.context = [[NSManagedObjectContext alloc] init];
 // 保存信息(比较重要的操作,每次更新和插入以及删除后必须做的操作)
 NSError *error = nil;
 BOOL result = [self.context save:&error];
 if (!result) {
 NSLog(@"添加数据失败:%@",error);
 if (fail) {
 fail(error);
 }
 } else {
 NSLog(@"添加数据成功");
 if (success) {
 success();
 }
 }
- NSManagedObjectModel
Core Data的模型文件,有点像SQLite的.sqlite文件(个人理解:表示一个.xcdatamodeld文件)
 // 创建方式
 // 1.主动加载指定名称的.xcdatamodeld资源
 //获取模型路径
 NSURL *modelURL = [[NSBundle mainBundle] URLForResource:modelName
 withExtension:@"momd"];
 //根据模型文件创建模型对象
 NSManagedObjectModel *model = [[NSManagedObjectModel alloc]
 initWithContentsOfURL:modelURL];
 // 2.从应用程序包中加载.xcdatamodeld模型文件
 NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
- NSPersistentStoreCoordinator - 持久化存储库,CoreData的存储类型(比如SQLite数据库就是其中一种)。
 用来将对象管理部分和持久化部分捆绑在一起,负责相互之间的交流(中介一样)
 用来设置CoreData存储类型和存储路径
 对象和数据库之间的交互不需要我们来关心,苹果帮我们做好了。我们只需要面向OC开发
 // 创建方式
 /**
 注意:创建NSPersistentStoreCoordinator前必须创建NSManagedObjectModel
 个人理解:好比在一个数据库中创建表前需要设置表的所有字段,
 这里传入NSManagedObjectModel模型(.xcdatamodeld模型文件),
 感觉就是让CoreData知道所有模型中的实体中的所有键值,
 从而好创建CoreData数据库
 */
 // 以传入NSManagedObjectModel模型方式初始化持久化存储库
 NSPersistentStoreCoordinator *persistent = [[NSPersistentStoreCoordinator alloc]
 initWithManagedObjectModel:model];
 /*
 持久化存储库的类型:
 NSSQLiteStoreType SQLite数据库
 NSBinaryStoreType 二进制平面文件
 NSInMemoryStoreType 内存库,无法永久保存数据
 虽然这3种类型的性能从速度上来说都差不多,但从数据模型中保留下来的信息却不一样
 在几乎所有的情景中,都应该采用默认设置,使用SQLite作为持久化存储库
 */
 // 添加一个持久化存储库并设置类型和路径,NSSQLiteStoreType:SQLite作为存储库
 NSError *error = nil;
 // 名字最好和.xcdatamodeld文件的名字一样
 NSString *sqlPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
 NSUserDomainMask, YES)
 lastObject]
 stringByAppendingPathComponent:@"xxx.sqlite"];
 [persistent addPersistentStoreWithType:NSSQLiteStoreType configuration:nil
 URL:[NSURL fileURLWithPath:sqlPath]
 options:nil
 error:&error];
 if (error) {
 NSLog(@"添加数据库失败:%@",error);
 if (fail) {
 fail(error);
 }
 } else {
 NSLog(@"添加数据库成功");
 // 设置上下文所要关联的持久化存储库(这一步千万不要忘记)
 self.context.persistentStoreCoordinator = self.persistent;
 if (success) {
 success();
 }
 }
- NSEntityDescription
用来描述实体(Entity):相当于数据库表中一组数据描述(纯属个人理解)
 通过Core Data从数据库中取出的对象,默认情况下都是NSManagedObject对象.
 NSManagedObject的工作模式有点类似于NSDictionary对象,通过键-值对来存取所有的实体属性.
 setValue:forkey:存储属性值(属性名为key);
 valueForKey:获取属性值(属性名为key).
 每个NSManagedObject都知道自己属于哪个NSManagedObjectContext
 // 创建方式(用于插入数据使用:获得实体,改变实体各个属性值,保存后就代表插入)
 /**
 注意:不能用 alloc init方式创建
 通过传入上下文和实体名称,创建一个名称对应的实体对象
 (相当于数据库一组数据,其中含有多个字段)
 个人感觉有种先插入一个新的Entity从而获得Entity,在进行各属性赋值
 */
 NSManagedObject *newEntity = [NSEntityDescription insertNewObjectForEntityForName:
 entityName
 inManagedObjectContext:self.context];
 
- CoreData的增删改查 - 上面说了这么多始终没描述如何去操作它,现在先说说大概步骤。 - insert
1.根据Entity名称和NSManagedObjectContext获取一个新的NSManagedObject
 NSManagedObject *newEntity = [NSEntityDescription
 insertNewObjectForEntityForName:entityName
 inManagedObjectContext:self.context];
 2.根据Entity中的键值,一一对应通过setValue:forkey:给NSManagedObject对象赋值
 [newEntity setValue:value forKey:key];
 3.保存修改
 NSError *error = nil;
 BOOL result = [self.context save:&error];
- delete
1.通过查询(设置好查询条件)请求取得需要删除的NSManagedObject的所有集合
 2.通过for循环调用deleteObject:方法进行逐个删除(个人怀疑这个for循环会不会导致性能问题),
 暂时没发现其它删除方法。
 [self.context deleteObject:entity];
 3.保存修改
- update
1.通过查询(设置好查询条件)请求取得需要修改的NSManagedObject的所有集合
 2.通过for循环调用NSManagedObject对象的setValue:forkey:方法给各个属性赋值
 3.保存修改
- read
1.创建NSFetchRequest查询请求对象
 NSFetchRequest *request = [[NSFetchRequest alloc] init];
 2.设置需要查询的实体描述NSEntityDescription
 NSEntityDescription *desc = [NSEntityDescription entityForName:self.entityName
 inManagedObjectContext:self.context];
 request.entity = desc;
 3.设置排序顺序NSSortDescriptor对象集合(可选)
 request.sortDescriptors = descriptorArray;
 4.设置条件过滤(可选)
 NSPredicate *predicate = [NSPredicate predicateWithFormat:filterStr];
 request.predicate = predicate;
 5.执行查询请求
 NSError *error = nil;
 // NSManagedObject对象集合
 NSArray *objs = [self.context executeFetchRequest:request error:&error];
 // 查询结果数目
 NSUInteger count = [self.context countForFetchRequest:request error:&error];从上面可以看出如果我们仅仅是简单的对CoreData进行增删改查的操作的话,稍微费点心思的就属查询这一块。里面涉及到了两个对象NSSortDescriptor和NSPredicate,分别用于设置排序和过滤查询条件的,尤其是NSPredicate,它不仅仅用于CoreData,还被经常用于数组的过滤。具体对这两个对象的介绍我就不说了,感觉这一篇写多了。下面我直接上代码。不在多讲了。 
 
- insert
- CoreData个人小封装 - 上面提到实体的创建因素导致了封装重用的难度,基本上新建一个.xcdatamodeld文件就得做好特意为它写一些操作接口的准备。 - CoreDataAPI.h/.m - //
 // CoreDataAPI.h
 // TedcallStorage
 //
 // Created by tedcall on 16/7/1.
 // Copyright © 2016年 pocket. All rights reserved.
 // #import <Foundation/Foundation.h> @interface CoreDataAPI : NSObject
 /**
 * 获取数据库存储的路径
 */
 @property (nonatomic,copy,readonly) NSString *sqlPath;
 /**
 * 获取.xcdatamodeld文件的名称
 */
 @property (nonatomic,copy,readonly) NSString *modelName;
 /**
 * 获取.xcdatamodeld文件中创建的实体的名称
 */
 @property (nonatomic,copy,readonly) NSString *entityName; /**
 * 创建CoreData数据库
 *
 * @param entityName 实体名称
 * @param modelName .xcdatamodeld文件名称(为nil则主动从程序包加载模型文件)
 * @param sqlPath 数据库存储的路径
 * @param success 成功回调
 * @param fail 失败回调
 *
 * @return 返回CoreDataAPI对象
 */
 - (instancetype)initWithCoreData:(NSString *)entityName modelName:(NSString *)modelName sqlPath:(NSString *)sqlPath success:(void(^)(void))success fail:(void(^)(NSError *error))fail; /**
 * 插入数据
 *
 * @param dict 字典中的键值对必须要与实体中的每个名字一一对应
 * @param success 成功回调
 * @param fail 失败回调
 */
 - (void)insertNewEntity:(NSDictionary *)dict success:(void(^)(void))success fail:(void(^)(NSError *error))fail; /**
 * 查询数据
 *
 * @param sequenceKeys 数组高级排序(数组里存放实体中的key,顺序按自己需要的先后存放即可),实体key来排序
 * @param isAscending 是否上升排序
 * @param filterStr 过滤语句
 * @param success 成功后结果回调
 * @param fail 失败回调
 */
 - (void)readEntity:(NSArray *)sequenceKeys ascending:(BOOL)isAscending filterStr:(NSString *)filterStr success:(void(^)(NSArray *results))success fail:(void(^)(NSError *error))fail; /**
 * 删除数据
 *
 * @param entity NSManagedObject
 * @param success 成功回调
 * @param fail 失败回调
 */
 - (void)deleteEntity:(NSManagedObject *)entity success:(void(^)(void))success fail:(void(^)(NSError *error))fail; /**
 * 更新数据
 *
 * @param success 成功回调
 * @param fail 失败回调
 */
 - (void)updateEntity:(void(^)(void))success fail:(void(^)(NSError *error))fail;
 @end- //
 // CoreDataAPI.m
 // TedcallStorage
 //
 // Created by tedcall on 16/7/1.
 // Copyright © 2016年 pocket. All rights reserved.
 // /**
 * 知识点:
 NSManagedObject:
 通过Core Data从数据库中取出的对象,默认情况下都是NSManagedObject对象.
 NSManagedObject的工作模式有点类似于NSDictionary对象,通过键-值对来存取所有的实体属性.
 setValue:forkey:存储属性值(属性名为key);
 valueForKey:获取属性值(属性名为key).
 每个NSManagedObject都知道自己属于哪个NSManagedObjectContext NSManagedObjectContext:
 负责数据和应用库之间的交互(CRUD,即增删改查、保存等接口都在这个对象中).
 所有的NSManagedObject都存在于NSManagedObjectContext中,所以对象和context是相关联的
 每个 context 和其他 context 都是完全独立的
 每个NSManagedObjectContext都知道自己管理着哪些NSManagedObject NSPersistentStoreCoordinator:
 添加持久化存储库,CoreData的存储类型(比如SQLite数据库就是其中一种)
 中间审查者,用来将对象图管理部分和持久化部分捆绑在一起,负责相互之间的交流(中介一样) NSManagedObjectModel:
 Core Data的模型文件 NSEntityDescription:
 用来描述实体:相当于数据库表中一组数据描述
 */ #import "CoreDataAPI.h"
 #import <CoreData/CoreData.h>
 @interface CoreDataAPI()
 /**
 * 数据模型对象
 */
 @property (nonatomic,strong) NSManagedObjectModel *model;
 /**
 * 上下文
 */
 @property (nonatomic,strong) NSManagedObjectContext *context;
 /**
 * 持久性存储区
 */
 @property (nonatomic,strong) NSPersistentStoreCoordinator *persistent;
 @end @implementation CoreDataAPI - (instancetype)initWithCoreData:(NSString *)entityName modelName:(NSString *)modelName sqlPath:(NSString *)sqlPath success:(void(^)(void))success fail:(void(^)(NSError *error))fail
 {
 if (self = [super init]) {
 // 断言(实体名称和存储路径是否为nil)
 // ... _entityName = entityName;
 _modelName = modelName;
 _sqlPath = sqlPath;
 // 初始化上下文
 self.context = [[NSManagedObjectContext alloc] init];
 if (modelName) {
 //获取模型路径
 NSURL *modelURL = [[NSBundle mainBundle] URLForResource:modelName withExtension:@"momd"];
 //根据模型文件创建模型对象
 self.model = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
 } else { // 从应用程序包中加载模型文件
 self.model = [NSManagedObjectModel mergedModelFromBundles:nil];
 } // 以传入模型方式初始化持久化存储库
 self.persistent = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.model];
 /*
 持久化存储库的类型:
 NSSQLiteStoreType SQLite数据库
 NSBinaryStoreType 二进制平面文件
 NSInMemoryStoreType 内存库,无法永久保存数据
 虽然这3种类型的性能从速度上来说都差不多,但从数据模型中保留下来的信息却不一样
 在几乎所有的情景中,都应该采用默认设置,使用SQLite作为持久化存储库
 */
 // 添加一个持久化存储库并设置类型和路径,NSSQLiteStoreType:SQLite作为存储库
 NSError *error = nil;
 [self.persistent addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:sqlPath] options:nil error:&error];
 if (error) {
 NSLog(@"添加数据库失败:%@",error);
 if (fail) {
 fail(error);
 }
 } else {
 NSLog(@"添加数据库成功");
 // 设置上下文所要关联的持久化存储库
 self.context.persistentStoreCoordinator = self.persistent;
 if (success) {
 success();
 }
 }
 } return self;
 } // 添加数据
 - (void)insertNewEntity:(NSDictionary *)dict success:(void(^)(void))success fail:(void(^)(NSError *error))fail
 {
 if (!dict||dict.allKeys.count == 0) return;
 // 通过传入上下文和实体名称,创建一个名称对应的实体对象(相当于数据库一组数据,其中含有多个字段)
 NSManagedObject *newEntity = [NSEntityDescription insertNewObjectForEntityForName:self.entityName inManagedObjectContext:self.context];
 // 实体对象存储属性值(相当于数据库中将一个值存入对应字段)
 for (NSString *key in [dict allKeys]) {
 [newEntity setValue:[dict objectForKey:key] forKey:key];
 }
 // 保存信息,同步数据
 NSError *error = nil;
 BOOL result = [self.context save:&error];
 if (!result) {
 NSLog(@"添加数据失败:%@",error);
 if (fail) {
 fail(error);
 }
 } else {
 NSLog(@"添加数据成功");
 if (success) {
 success();
 }
 }
 } // 查询数据
 - (void)readEntity:(NSArray *)sequenceKeys ascending:(BOOL)isAscending filterStr:(NSString *)filterStr success:(void(^)(NSArray *results))success fail:(void(^)(NSError *error))fail
 {
 // 1.初始化一个查询请求
 NSFetchRequest *request = [[NSFetchRequest alloc] init];
 // 2.设置要查询的实体
 NSEntityDescription *desc = [NSEntityDescription entityForName:self.entityName inManagedObjectContext:self.context];
 request.entity = desc;
 // 3.设置查询结果排序
 if (sequenceKeys&&sequenceKeys.count>0) { // 如果进行了设置排序
 NSMutableArray *array = [NSMutableArray array];
 for (NSString *key in sequenceKeys) {
 /**
 * 设置查询结果排序
 * sequenceKey:根据某个属性(相当于数据库某个字段)来排序
 * isAscending:是否升序
 */
 NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:key ascending:isAscending];
 [array addObject:sort];
 }
 if (array.count>0) {
 request.sortDescriptors = array;// 可以添加多个排序描述器,然后按顺序放进数组即可
 }
 }
 // 4.设置条件过滤
 if (filterStr) { // 如果设置了过滤语句
 NSPredicate *predicate = [NSPredicate predicateWithFormat:filterStr];
 request.predicate = predicate;
 }
 // 5.执行请求
 NSError *error = nil;
 NSArray *objs = [self.context executeFetchRequest:request error:&error]; // 获得查询数据数据集合
 if (error) {
 if (fail) {
 fail(error);
 }
 } else{
 if (success) {
 success(objs);
 }
 }
 } // 更新数据
 - (void)updateEntity:(void(^)(void))success fail:(void(^)(NSError *error))fail
 {
 NSError *error = nil;
 [self.context save:&error];
 if (error) {
 NSLog(@"删除失败:%@",error);
 if (fail) {
 fail(error);
 }
 } else {
 if (success) {
 success();
 }
 } } // 删除数据
 - (void)deleteEntity:(NSManagedObject *)entity success:(void(^)(void))success fail:(void(^)(NSError *error))fail
 {
 // 传入需要删除的实体对象
 [self.context deleteObject:entity];
 // 同步到数据库
 NSError *error = nil;
 [self.context save:&error];
 if (error) {
 NSLog(@"删除失败:%@",error);
 if (fail) {
 fail(error);
 }
 } else {
 if (success) {
 success();
 }
 }
 }
 @end
- 用法(UploadCoreDataAPI.h/.m) - //
 // UploadCoreDataAPI.h
 // TedcallStorage
 //
 // Created by tedcall on 16/7/14.
 // Copyright © 2016年 pocket. All rights reserved.
 // #import <Foundation/Foundation.h>
 @class ResourceModel,DownLoadModel;
 @interface UploadCoreDataAPI : NSObject
 /**
 * 上传数据库模型名称
 */
 @property (nonatomic,copy,readonly) NSString *coreDataModelName;
 /**
 * 上传数据库实体名称
 */
 @property (nonatomic,copy,readonly) NSString *coreDataEntityName;
 /**
 * 上传数据库存储路径
 */
 @property (nonatomic,copy,readonly) NSString *coreDataSqlPath;
 + (instancetype)sharedInstance;
 /**
 * 插入上传记录
 *
 * @param model 数据模型
 * @param success 成功回调
 * @param fail 失败回调
 */
 - (void)insertUploadModel:(ResourceModel *)model success:(void(^)(void))success fail:(void(^)(NSError *error))fail; /**
 * 更新上传记录
 *
 * @param model 数据模型
 * @param success 成功回调
 * @param fail 失败回调
 */
 - (void)updateUploadModel:(DownLoadModel *)model success:(void(^)(void))success fail:(void(^)(NSError *error))fail; /**
 * 删除一条上传记录
 *
 * @param model 数据模型
 * @param success 成功回调
 * @param fail 失败回调
 */
 - (void)deleteUploadModel:(DownLoadModel *)model success:(void(^)(void))success fail:(void(^)(NSError *error))fail; /**
 * 删除所有上传记录
 *
 * @param success 成功回调
 * @param fail 失败回调
 */
 - (void)deleteAllUploadModel:(void(^)(void))success fail:(void(^)(NSError *error))fail; /**
 * 查询上传数据库所有数据
 *
 * @param success 成功回调(finishArray:已完成(DownLoadModel对象数组) unfinishedArray:未完成(DownLoadModel对象数组))
 * @param fail 失败回调
 */
 - (void)readAllUploadModel:(void(^)(NSArray *finishArray,NSArray *unfinishedArray))success fail:(void(^)(NSError *error))fail;
 @end- //
 // UploadCoreDataAPI.m
 // TedcallStorage
 //
 // Created by tedcall on 16/7/14.
 // Copyright © 2016年 pocket. All rights reserved.
 // #import "UploadCoreDataAPI.h"
 #import "CoreDataAPI.h"
 #import "ResourceModel.h"
 #import "DownLoadModel.h"
 static NSString * const modelName = @"Upload";
 static NSString * const entityName = @"UploadEntity";
 static NSString * const sqliteName = @"Upload.sqlite";
 @interface UploadCoreDataAPI()
 @property (nonatomic,strong) CoreDataAPI *uploadData;
 @end
 @implementation UploadCoreDataAPI
 static UploadCoreDataAPI *uploadCoreData = nil;
 + (instancetype)sharedInstance
 {
 static dispatch_once_t onceToken;
 dispatch_once(&onceToken, ^{
 uploadCoreData = [[UploadCoreDataAPI alloc] init];
 }); return uploadCoreData;
 } + (instancetype)allocWithZone:(struct _NSZone *)zone
 {
 static dispatch_once_t onceToken;
 dispatch_once(&onceToken, ^{
 if (uploadCoreData == nil) {
 uploadCoreData = [super allocWithZone:zone];
 }
 }); return uploadCoreData;
 } - (instancetype)init
 {
 if (self = [super init]) {
 [self initUploadCoreData];
 }
 return self;
 } - (void)initUploadCoreData
 {
 _coreDataEntityName = entityName;
 _coreDataModelName = modelName;
 _coreDataSqlPath = [[[FileManager shardInstance] getDocumentPath] stringByAppendingPathComponent:sqliteName];
 self.uploadData = [[CoreDataAPI alloc] initWithCoreData:self.coreDataEntityName modelName:self.coreDataModelName sqlPath:self.coreDataSqlPath success:^{
 NSLog(@"initUploadCoreData success");
 } fail:^(NSError *error) {
 NSLog(@"initUploadCoreData fail");
 }]; } #pragma mark - -- 插入上传记录
 - (void)insertUploadModel:(ResourceModel *)model success:(void(^)(void))success fail:(void(^)(NSError *error))fail
 {
 NSString *fileName = model.fileName;
 NSString *fileSize = [NSString stringWithFormat:@"%.2lf",model.size];
 NSString *urlPath = model.path;
 NSNumber *time = [NSNumber numberWithInt:[[DateManager sharedInstance] getSecondsSince1970]];
 NSNumber *fileType = [NSNumber numberWithInt:model.fileType];
 NSNumber *finishStatus = [NSNumber numberWithBool:NO];
 NSDictionary *dict = NSDictionaryOfVariableBindings(fileName,fileSize,urlPath,time,fileType,finishStatus); [self.uploadData insertNewEntity:dict success:^{
 if (success) {
 success();
 }
 } fail:^(NSError *error) {
 if (fail) {
 fail(error);
 }
 }];
 } #pragma mark - -- 更新上传记录
 - (void)updateUploadModel:(DownLoadModel *)model success:(void(^)(void))success fail:(void(^)(NSError *error))fail
 {
 NSString *filterStr = [NSString stringWithFormat:@"time = %d AND urlPath = '%@' AND fileName = '%@'",model.time,model.urlPath,model.fileName];
 [self.uploadData readEntity:nil ascending:YES filterStr:filterStr success:^(NSArray *results) {
 if (results.count>0) {
 NSManagedObject *obj = [results firstObject];
 [obj setValue:[NSNumber numberWithBool:model.finishStatus] forKey:@"finishStatus"];
 [self.uploadData updateEntity:^{
 if (success) {
 success();
 }
 } fail:^(NSError *error) {
 if (fail) {
 fail(error);
 }
 }];
 }
 } fail:^(NSError *error) {
 if (fail) {
 fail(error);
 }
 }];
 } #pragma mark - -- 删除一条上传记录
 - (void)deleteUploadModel:(DownLoadModel *)model success:(void(^)(void))success fail:(void(^)(NSError *error))fail
 {
 NSString *filterStr = [NSString stringWithFormat:@"time = %d AND urlPath = '%@' AND fileName = '%@'",model.time,model.urlPath,model.fileName];
 [self.uploadData readEntity:nil ascending:YES filterStr:filterStr success:^(NSArray *results) {
 if (results.count>0) {
 NSManagedObject *obj = [results firstObject];
 [self.uploadData deleteEntity:obj success:^{
 if (success) {
 success();
 }
 } fail:^(NSError *error) {
 if (fail) {
 fail(error);
 }
 }];
 }
 } fail:^(NSError *error) {
 if (fail) {
 fail(error);
 }
 }];
 } #pragma mark - -- 删除所有上传记录
 - (void)deleteAllUploadModel:(void(^)(void))success fail:(void(^)(NSError *error))fail
 {
 [self.uploadData readEntity:nil ascending:YES filterStr:nil success:^(NSArray *results) {
 for (NSManagedObject *obj in results){
 [self.uploadData deleteEntity:obj success:^{
 if (success) {
 success();
 }
 } fail:^(NSError *error) {
 if (fail) {
 fail(error);
 }
 }];
 }
 } fail:^(NSError *error) {
 if (fail) {
 fail(error);
 }
 }];
 } #pragma mark - -- 查询所有上传记录
 - (void)readAllUploadModel:(void(^)(NSArray *finishArray,NSArray *unfinishedArray))success fail:(void(^)(NSError *error))fail
 {
 [self.uploadData readEntity:nil ascending:YES filterStr:nil success:^(NSArray *results) {
 NSMutableArray *finishArray = [NSMutableArray array];
 NSMutableArray *unfinishedArray = [NSMutableArray array];
 for (NSManagedObject *obj in results) {
 DownLoadModel *model = [[DownLoadModel alloc] init];
 // 获取数据库中各个键值的值
 model.fileName = [obj valueForKey:@"fileName"];
 model.fileSize = [obj valueForKey:@"fileSize"];
 model.urlPath = [obj valueForKey:@"urlPath"];
 model.time = [[obj valueForKey:@"time"] intValue];
 model.fileType = [[obj valueForKey:@"fileType"] intValue];
 model.imageData = [obj valueForKey:@"imageData"];
 model.finishStatus = [[obj valueForKey:@"finishStatus"] intValue];
 if (model.finishStatus) {
 [finishArray addObject:model];
 } else {
 [unfinishedArray addObject:model];
 } }
 if (success) {
 success(finishArray,unfinishedArray);
 }
 } fail:^(NSError *error) {
 if (fail) {
 fail(error);
 }
 }];
 }
 @end
 
结语:以上纯属个人摸索和个人总结,不对的地方忘指出。其实在实际开发中不仅仅是增删改查这么简单,有时候会出现APP已经发布,但是数据库后续改变了,这就涉及到数据库的迁移,以及一些数据安全问题和线程等都是比较深入的,有专研精神的可以自行搜索相关资料。互勉!!!
iOS CoreData 介绍和使用(以及一些注意事项)的更多相关文章
- iOS CoreData介绍和使用(以及一些注意事项)
		iOS CoreData介绍和使用(以及一些注意事项) 最近花了一点时间整理了一下CoreData,对于经常使用SQLite的我来说,用这个真的有点用不惯,个人觉得实在是没发现什么亮点,不喜勿喷啊.不 ... 
- iOS框架介绍
		iOS框架介绍 Cocoa Touch GameKit 实现对游戏中心的支持,让用户能够在线共享他们的游戏相关的信息 iOS设备之间蓝牙数据传输 从iOS7开始过期 局域网游 ... 
- iOS CoreData (二) 版本升级和数据库迁移
		前言:最近ChinaDaily项目需要迭代一个新版本,在这个版本中CoreData数据库模型上有新增表.实体字段的增加,那么在用户覆盖安装程序时就必须要进行CoreData数据库的版本升级和旧数据迁移 ... 
- IOS CoreData 多表查询(下)
		http://blog.csdn.net/fengsh998/article/details/8123392 在iOS CoreData中,多表查询上相对来说,没有SQL直观,但COREDATA的功能 ... 
- iOS CoreData技术学习资源汇总
		一.CoreData学习指引 1. 苹果官方:Core Data Programming Guide 什么是CoreData? 创建托管对象模型 初始化Core Data堆栈 提取对象 创建和修改自定 ... 
- IOS CoreData 多表查询demo解析
		在IOS CoreData中,多表查询上相对来说,没有SQL直观,但CoreData的功能还是可以完成相关操作的. 下面使用CoreData进行关系数据库的表与表之间的关系演示.生成CoreData和 ... 
- iOS CoreData (一) 增删改查
		代码地址如下:http://www.demodashi.com/demo/11041.html Core Data是iOS5之后才出现的一个框架,本质上是对SQLite的一个封装,它提供了对象-关系映 ... 
- 一个iOS 框架介绍:MKNetworkKit
		http://blog.csdn.net/kmyhy/article/details/12276287 http://blog.csdn.net/mobailwang/article/details/ ... 
- CoreData介绍
		http://blog.csdn.net/zh952016281/article/details/52105683 写在前面 在CoreData中有一些常用的类,称呼可能各不相同.所以这里先约定一些关 ... 
随机推荐
- h5-列表
			aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAX4AAAInCAIAAAAQ0aUJAAAgAElEQVR4nOy9eVxb153wnZk+z/t53n ... 
- 由GPS坐标计算半径
			在实际应用当中,一般是通过一个个体的编码来查找该编码对应的地区中心的经纬度,然后再根据这些经纬度来计算彼此的距离,从而估算出某些群体之间的大致距离范围(比如酒店旅客的分布范围-各个旅客的邮政编码对应的 ... 
- Noip蒟蒻专用模板
			目录 模板 数论 线性筛素数 线性筛欧拉 裴蜀定理 卢卡斯定理 矩阵快速幂 逆元 高斯消元 图论 割点 最小生成树 倍增 SPFA 负环 堆优化迪杰斯特拉 匈牙利 数据结构 树状数组 ST表 线段树 ... 
- Python中functools模块函数解析
			Python自带的 functools 模块提供了一些常用的高阶函数,也就是用于处理其它函数的特殊函数.换言之,就是能使用该模块对可调用对象进行处理. functools模块函数概览 functool ... 
- ROS-OPENCV
			前言:opencv是一个开源的跨平台计算机视觉库. 前提:1.已下载并编译了相关功能包集,如还未下载,可通过git下载:https://github.com/huchunxu/ros_explorin ... 
- 错误:com.android.builder.packaging.DuplicateFileException: Duplicate files copied
			File2: C:\Users\guoxw\.gradle\caches\modules-2\files-2.1\org.jsoup\jsoup\1.10.3\b842f960942503cf1abb ... 
- (转)硬盘结构,主引导记录MBR,硬盘分区表DPT,主分区、扩展分区和逻辑分区,电脑启动过程
			硬盘结构硬盘有很多盘片组成,每个盘片的每个面都有一个读写磁头.如果有N个盘片.就有2N个面,对应2N个磁头(Heads),从0.1.2开始编号.每个盘片的半径均为固定值R的同心圆再逻辑上形成了一个以电 ... 
- Unity脚本中可以引用的类型
			Hierarchy(层级视图)面板里的对象,或者 Project(工程视图)里的Prefab. 
- ZBrush曲线功能介绍
			在ZBrush®中曲线功能是一个非常有用的工具.插入笔刷,曲线笔刷,拓扑和许多地方都会用到它.生成曲线的方式有很多种.可以使用重拓扑引导线,可以使用笔触菜单下曲线功能中的框架网格,可以使用ZBrush ... 
- jsp基本内置标签
			<jsp:foward page="url"> <jsp:param value=" " name=" "/> &l ... 
