自己负责一个项目走过来, 遇到很多需求, 印象最深且最让自己引以为豪的还是 CoreData 的使用了, 公司其他人都不会用, 我选择了这个作为存储数据的杀手锏, 说实话使用的过程遇到很多问题, 也挺让人头疼的, 但还是一步一步走过来了......也让我相信很多时候觉得不可能解决的问题, 再研究研究是可以解决的!
开始正题:
现在说的是 项目中 创建CoreData Model
1.创建 CoreData Model
这里说一下创建好的类文件默认显示的路径会在项目名路径下, 如果你在创建之前已经指定好路径, 其实是在你指定的路径的, 我们可以将位置移一下; 但就全局来看, 当你想保存多个模型时, 放在默认位置就好
这里编译一下
出现报错, 来到这个文件中
到这里就可以CoreData 模型也就创建完成了, 编译成功
2.创建 CoreDataManager 管理文件
#import
#import
#define kCoreDataManager [CoreDataManager shareInstane]
#define kFilePathName @"Announce"
@interface CoreDataManager : NSObject
+(CoreDataManager *)shareInstane;
#pragma mark CoreData Stack
// 管理对象上下文
@property(nonatomic,strong)NSManagedObjectContext *managedObjectContext;
// 对象模型
@property(nonatomic,strong)NSManagedObjectModel *managedObjectModel;
// 存储调度器
@property(nonatomic,strong)NSPersistentStoreCoordinator *persistentStoreCoordinator;
#pragma mark -Funcation
// 保存到数据库
- (void)save;
// 清空数据库
- (void)deletAllEntities;
// 插入数据
- (void)insertCoreData:(NSMutableArray*)dataArray;
/**
查询并返回数据
@param pageSize 一个查询多少条
@param currentPage 当前页数(多少条算一页)
@param predicate 查询谓词条件
@param entityName 查询的实体模型名称
@param sortKey 排序条件(根据哪个 key 排序)
@return 返回查询到的数据
*/
- (NSArray *)selectData:(int)pageSize andOffset:(int)currentPage andPredicate:(NSPredicate *)predicate entityName:(NSString *)entityName sortKey:(NSString *)sortKey;
// 判断将要保存的数据是否已经存在于 coreData 中
- (BOOL)fetchAllObjectsWithSaveDataArr:(NSMutableArray *)array;
// 更新coreData 中的字段(需要更新的字段参数可自定义)
- (void)updateData:(NSString*)newsId withIsLook:(NSString*)islook;
.m 文件中
#import "CoreDataManager.h"
#import "Announcement+CoreDataClass.h"
#import "Contact+CoreDataClass.h"
@implementation CoreDataManager
// 管理模型上下文
@synthesize managedObjectContext = _managedObjectContext;
// 管理对象模型
@synthesize managedObjectModel = _managedObjectModel;
// 存储调度器
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
+(CoreDataManager *)shareInstane
{
static CoreDataManager *manager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manager = [[CoreDataManager alloc] init];
});
return manager;
}
// 懒加载
- (NSManagedObjectContext *)managedObjectContext
{
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
//1.创建管理对象上下文 参数是指定上下文的线程环境 建议使用:NSMainQueueConcurrencyType主线操作(主线程操作没有延迟) NSPrivateQueueConcurrencyType(子线程操作数据存储会有一定延迟)
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
//2.设置存储调度器(存储数据时 对象上下文负责给存储调度器发送指令)
[_managedObjectContext setPersistentStoreCoordinator:self.persistentStoreCoordinator];
//3.返回
return _managedObjectContext;
}
- (NSManagedObjectModel *)managedObjectModel
{
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
//1.创建对象模型(参数:值得是模型文件 xcdatamodeld路径)
//注意:模型文件的后缀不能使用xcdatamodeld,否则会崩溃。 只能用momd
//这个是保存单个模型时使用
// _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:[[NSBundle mainBundle]URLForResource:@"IAAnnounce" withExtension:@"momd"]];
//2.使用合并的方式创建对象模型(上面的操作创建模型此时只能保存一个固定的数据库xc文件,用该方法则可以同时管理多个模型xc文件)
//参数是一个bundle路径的数组 如果设为nil,则会自动帮你寻找整个项目中所有的路径下的cx模型文件
_managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
//2.返回
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSString *storeType = NSSQLiteStoreType;
NSError *error = NULL;
// NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"IAAnnounce.db"];
// NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
// [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
// [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];
// if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// NSLog(@"Error : %@\n", [error localizedDescription]);
// NSAssert1(YES, @"Failed to create store %@ with NSSQLiteStoreType", [storeURL path]);
// }
//1.创建存储调度器 参数:对象模型
// _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:self.managedObjectModel];
//2.给存储调度器添加存储器(存储调度器的作用是调度存储器)
/**storeType
NSSQLiteStoreType 数据库形式存储
NSXMLStoreType XML形式存储
NSBinaryStoreType 二进制存储
NSInMemoryStoreType 内存形式存储
*/
/**
type:
configuration:配置 一般为nil,默认设置
URL:数据库文件保存的路径
options:参数信息 一般为nil,默认设置
error:报错
*/
NSURL *fileURL = [[self getDocumentUrl] URLByAppendingPathComponent:[NSString stringWithFormat:@"%@.db",kFileName]];
[_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:fileURL options:nil error:nil];
//3.返回
return _persistentStoreCoordinator;
}
#pragma mark - Application's Documents directory
// Returns the URL to the application's Documents directory.
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
// 保存数据
- (void)save
{
NSError *errol = nil;
//数据库的增删改查保存等操作都是操作上下文
[self.managedObjectContext save:&errol];
if (errol == nil) {
NSLog(@"保存到数据库成功");
} else {
NSLog(@"%@",errol.description);
}
}
// 删除所有数据
- (void)deletAllEntities
{
//清空数据库快捷方式可以直接删除数据库文件
NSString *filePath1 = [NSString stringWithFormat:@"%@/Documents/%@.db",NSHomeDirectory(),kFilePathName];
NSString *filePath2 = [NSString stringWithFormat:@"%@/Documents/%@.db-shm",NSHomeDirectory(),kFilePathName];
NSString *filePath3 = [NSString stringWithFormat:@"%@/Documents/%@.db-wal",NSHomeDirectory(),kFilePathName];
NSError *error;
[[NSFileManager defaultManager] removeItemAtPath:filePath1 error:&error];
[[NSFileManager defaultManager] removeItemAtPath:filePath2 error:&error];
[[NSFileManager defaultManager] removeItemAtPath:filePath3 error:&error];
if (error == nil) {
NSLog(@"清除数据库成功");
} else {
NSLog(@"%@",error.description);
}
}
// 插入数据
- (void)insertCoreData:(NSMutableArray*)dataArray
{
// 创建管理对象上下文
NSManagedObjectContext *context = [self managedObjectContext];
// 判断数据是否重复
BOOL result = [self fetchAllObjectsWithSaveDataArr:dataArray];
if (result) { return ; }
// 将传进来的数据遍历, 保存到 coreData 模型中
for (AnnounceModel *info in dataArray) {
// 实体描述器生成一个新的实体模型
AnnounceMent *newsInfo = [NSEntityDescription insertNewObjectForEntityForName:announcement inManagedObjectContext:context];
// ******注意: 传进来的数据保存时一定要与 coreData 实体中字段类型相对应否则很容易引起崩溃
newsInfo.content = info.content;
newsInfo.title = info.title;
newsInfo.islook = info.islook;
newsInfo.createDate = [NSString stringWithFormat:@"%@",info.createDate];
newsInfo.notice_id = [NSString stringWithFormat:@"%@",info.notice_id];
newsInfo.path = info.path;
// 保存到数据库中
[kCoreDataManager save];
}
}
// 判断是否已存有相同数据
- (BOOL)fetchAllObjectsWithSaveDataArr:(NSMutableArray *)array
{
NSManagedObjectContext *context = [self managedObjectContext];
//首先你需要建立一个request查询条件 announcement: 是你创建的实体entity 名称(我这里使用的宏定义)
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:announcement inManagedObjectContext:context]];
NSError *error = nil;
//这里获取到的是一个数组,你需要取出你要更新的那个obj
//在没有谓词查询条件下, 取出的是所有
NSArray *result = [context executeFetchRequest:request error:&error];
for (AnnounceModel *info in array) {
for (AnnounceMent *obj in result) {
// NSLog(@"obj.notice_id: %@ / info.notice_id: %@",obj.notice_id, info.notice_id);
if ([obj.notice_id.description isEqualToString: info.notice_id.description]) {
// NSLog(@"id 相同");
return YES;
}
}
}
return NO;
}
// 根据查询条件查询数据
- (NSArray *)selectData:(int)pageSize andOffset:(int)currentPage andPredicate:(NSPredicate *)predicate entityName:(NSString *)entityName sortKey:(NSString *)sortKey
{
NSManagedObjectContext *context = [self managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:context];
[fetchRequest setEntity:entity ];
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:sortKey ascending:NO];
fetchRequest.sortDescriptors = @[sort];
// 限定查询结果的数量 setFetchLimit
// 查询的偏移量 setFetchOffset
if (pageSize != 0) {
[fetchRequest setFetchLimit:pageSize];
[fetchRequest setFetchOffset:currentPage*pageSize];
}
if (predicate != nil) {
[fetchRequest setPredicate:predicate];
}
NSError *error;
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
return fetchedObjects;
}
// 更新数据
- (void)updateData:(NSString *)newsId withIsLook:(NSString*)islook
{
NSManagedObjectContext *context = [self managedObjectContext];
// 谓词
NSPredicate *predicate = [NSPredicate
predicateWithFormat:@"notice_id==%@", newsId.description];
//首先你需要建立一个request
NSFetchRequest * request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:announcement inManagedObjectContext:context]];
[request setPredicate:predicate];//这里相当于sqlite中的查询条件,具体格式参考苹果文档
//https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Predicates/Articles/pCreating.html
NSError *error = nil;
NSArray *result = [context executeFetchRequest:request error:&error];//这里获取到的是一个数组,你需要取出你要更新的那个obj
for (AnnounceModel *info in result) {
info.islook = islook;
}
//保存
if ([context save:&error]) {
//更新成功
NSLog(@"更新成功");
}
}
这些就是基本的 CoreData 操作