一、CoreData的簡單理解
CoreData
是一個(gè)模型層的技術(shù),也是一種持久化技術(shù),它能將模型對象的狀態(tài)持久化到磁盤里敬辣,我們不需要使用SQL
語句就能對它進(jìn)行操作雪标。CoreData
不是一個(gè)數(shù)據(jù)庫但是可以使用數(shù)據(jù)庫來存儲(chǔ)數(shù)據(jù),也可以使用其他方式溉跃,比如:數(shù)據(jù)庫文件
村刨,XML
,二進(jìn)制文件
撰茎,內(nèi)存
等嵌牺。CoreData
提供了對象-關(guān)系映射(ORM)
功能。能夠?qū)崿F(xiàn)數(shù)據(jù)庫數(shù)據(jù)和OC
對象的相互轉(zhuǎn)換,在這個(gè)轉(zhuǎn)換過程中我們不需要編寫任何SQL
語句逆粹。為什么要使用
CoreData
極大的減少Model
層的代碼量
優(yōu)化了使用SQLite
時(shí)候的性能
提供了可視化設(shè)計(jì)
二募疮、CoreData的使用
1、創(chuàng)建步驟
- 如果你是一個(gè)新的項(xiàng)目僻弹,可以創(chuàng)建項(xiàng)目的時(shí)候選擇
CoreData
如圖
- 如果是老的項(xiàng)目之前沒有使用
CoreData
阿浓,則按照如下的步驟:
第一步:先創(chuàng)建.xcdatamodeld
文件(右鍵 -> New File -> iOS -> Core Data ->Data Model)
第二步:命名然后創(chuàng)建(這里的名字要在后面操作的時(shí)候使用,要命好名字)
成功
2蹋绽、創(chuàng)建CodeDataMode
實(shí)體芭毙,并在實(shí)體中添加我們需要的鍵值如圖
3、創(chuàng)建實(shí)體關(guān)聯(lián)文件
-
自動(dòng)創(chuàng)建實(shí)體關(guān)聯(lián)文件
創(chuàng)建好實(shí)體對象XXX.xcdatamodeld
之后卸耘,右側(cè)屬性欄Code Generation
下面的Language
默認(rèn)為Swift
退敦,這里使用OC
,就改成Objective-C
蚣抗;Codegen
默認(rèn)為Class Definition
侈百,無需更改。通過Xcode
的Build
會(huì)自動(dòng)生成對應(yīng)的實(shí)體關(guān)聯(lián)文件忠聚,但是這些文件不會(huì)在目錄中顯示出來设哗,對應(yīng)的格式為:
//格式
實(shí)體名(表名)+CoreDataClass.h
實(shí)體名(表名)+CoreDataClass.m
實(shí)體名(表名)+CoreDataProperties.h
實(shí)體名(表名)+CoreDataProperties.m
//例如,實(shí)體名(表名)為Video两蟀,對應(yīng)的關(guān)聯(lián)文件為:
CoreDataMode+CoreDataClass.h
CoreDataMode+CoreDataClass.m
CoreDataMode+CoreDataProperties.h
CoreDataMode+CoreDataProperties.m
使用對應(yīng)的實(shí)體時(shí)网梢,導(dǎo)入對應(yīng)的頭文件即可颜启,例如:
#import "CoreDataMode+CoreDataProperties.h"
-
手動(dòng)創(chuàng)建實(shí)體關(guān)聯(lián)文件
實(shí)體對象XXX.xcdatamodeld
里面的Codegen
一定得設(shè)置為Manual/None
巨税,否則報(bào)文件重復(fù)錯(cuò)誤降狠,選中實(shí)體确垫,點(diǎn)擊Editor
帜慢,點(diǎn)擊Create NSManagedObject Subclass…
生成實(shí)體關(guān)聯(lián)文件:
手動(dòng)創(chuàng)建好關(guān)聯(lián)文件之后计技,目錄如下圖所示忠蝗,用的時(shí)候?qū)雽?yīng)的Properties
頭文件即可:
4 基茵、使用相應(yīng)的類
-
NSManagedObjectContext
數(shù)據(jù)庫操作:NSManagedObjectContext
被管理的對象上下文(對數(shù)據(jù)直接操作)
NSManagedObjectContext
:等同于一個(gè)容器膛堤,用來存儲(chǔ)從數(shù)據(jù)庫中轉(zhuǎn)換出來的所有的OC
對象手趣。我們的增刪改查操作直接對這個(gè)類使用來獲得或者修改需要的OC
對象,它能夠調(diào)用NSPersistentStoreCoordinator
類實(shí)現(xiàn)對數(shù)據(jù)庫的同步肥荔,這個(gè)對象有點(diǎn)像SQLite
對象(用來管理.xcdatamodeld
中的數(shù)據(jù))绿渣。
負(fù)責(zé)數(shù)據(jù)和應(yīng)用庫之間的交互(CRUD
,即增刪改查燕耿、保存等接口都是用這個(gè)對象調(diào)用)中符。
每個(gè)NSManagedObjectContext
和其他NSManagedObjectContext
都是完全獨(dú)立的。
所有的NSManagedObject
(個(gè)人理解:實(shí)體數(shù)據(jù))都存在于NSManagedObjectContext
中誉帅。
每個(gè)NSManagedObjectContext
都知道自己管理著哪些NSManagedObject
(實(shí)體數(shù)據(jù))
可以通過TA去訪問底層的框架對象集合淀散,這些對象集合統(tǒng)稱為持久化堆棧(persistence stack)
——它在應(yīng)用程序和外部數(shù)據(jù)存儲(chǔ)的對象之間提供訪問通道
-
NSManagedObject
NSManagedObject
的工作模式有點(diǎn)類似于NSDictionary
對象右莱,通過鍵-值對來存取所有的實(shí)體屬性。NSManagedObject
:數(shù)據(jù)庫中的數(shù)據(jù)轉(zhuǎn)換而來的OC
對象
setValue:forkey
:存儲(chǔ)屬性值(屬性名為key
);
valueForKey
:獲取屬性值(屬性名為key
)档插。
每個(gè)NSManagedObject
都知道自己屬于哪個(gè)NSManagedObjectContext
用于插入數(shù)據(jù)使用:獲得實(shí)體慢蜓,改變實(shí)體各個(gè)屬性值,保存后就代表插入
-
NSEntityDescription
NSEntityDescription
用來描述實(shí)體(Entity
) 表格結(jié)構(gòu): 相當(dāng)于數(shù)據(jù)庫中的一個(gè)表阀捅,TA
描述一種抽象數(shù)據(jù)類型
通過Core Data
從數(shù)據(jù)庫中取出的對象胀瞪,默認(rèn)情況下都是NSManagedObject
對象。
+insertNewObjectForEntityForName:inManagedObjectContext
: 工廠方法饲鄙,根據(jù)給定的Entity
描述凄诞,生成相應(yīng)的NSManagedObject
對象,并插入到ManagedObjectContext
中
LHModel * model = [NSEntityDescription insertNewObjectForEntityForName:@“CoreDataMode” inManagedObjectContext:self.managedObjectContext];
通過上面的代碼可以得到model
這個(gè)表的實(shí)例忍级,然后可以使用這個(gè)實(shí)例去為表中的屬性賦值
model.title = @“標(biāo)題”;
model.content = @“內(nèi)容”;
-
NSPersistentStoreCoordinator
NSPersistentStoreCoordinator
持久化存儲(chǔ)庫帆谍,CoreData
的存儲(chǔ)類型(比如SQLite
數(shù)據(jù)庫就是其中一種)。
用來將對象管理部分和持久化部分捆綁在一起轴咱,負(fù)責(zé)相互之間的交流
用來設(shè)置CoreData
存儲(chǔ)類型和存儲(chǔ)路徑
使用Core Data document
類型的應(yīng)用程序汛蝙,通常會(huì)從磁盤上的數(shù)據(jù)文中中讀取或存儲(chǔ)數(shù)據(jù),這寫底層的讀寫就由Persistent Store Coordinator
來處理朴肺。一 般我們無需與它直接打交道來讀寫文件窖剑,Managed Object Context
在背后已經(jīng)為我們調(diào)用Persistent Store Coordinator
做了這部分工作
NSPersistentStoreCoordinator
:通過解析結(jié)果去實(shí)現(xiàn)數(shù)據(jù)庫和OC
對象之間的相互轉(zhuǎn)換,主要是操作數(shù)據(jù)庫的戈稿,我們一般用不上西土,由系統(tǒng)處理
-
NSManagedObjectModel
NSManagedObjectModel Core Data
的模型文件,有點(diǎn)像SQLite的.sqlite
文件(個(gè)人理解:表示一個(gè).xcdatamodeld
文件)應(yīng)用程序的數(shù)據(jù)模型鞍盗,數(shù)據(jù)庫中所有表格和他們之間的聯(lián)系
NSManagedObjectModel
:負(fù)責(zé)讀取解析.momod
文件
NSManagedObjectModel * model = [self managedObjectModel];
//獲取實(shí)例
NSDictionary * entities = [model entitiesByName];
//entitiesByName
得到所有的表的名字
NSEntityDescription * entity = [entities valueForKey:@“CoreDataModel”];
//從里面找出名為Student
的表
5需了、具體實(shí)現(xiàn) 創(chuàng)建CoreDataManager 類
CoreDataManager.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@interface CoreDataManager : NSObject
/**
* 上下文 容器
* 存放的是 所有從數(shù)據(jù)庫中取出的轉(zhuǎn)換成OC對象
*/
@property (strong, nonatomic) NSManagedObjectContext * managedObjectContext;
/* 讀取解析 .momd文件中的內(nèi)容 */
@property (strong, nonatomic) NSManagedObjectModel * managedObjectModel;
/* 連接的類,處理數(shù)據(jù)庫數(shù)據(jù)和OC數(shù)據(jù)底層的相互轉(zhuǎn)換 */
@property (strong, nonatomic) NSPersistentStoreCoordinator * persistentStoreCoordinator;
/**
單例
@return CoreDataManager
*/
+ (instancetype)sharedInstance;
/**
插入數(shù)據(jù)
@param dict 字典中的鍵值對必須要與實(shí)體中的每個(gè)名字一一對應(yīng)
@param success 成功回調(diào)
@param fail 失敗回調(diào)
*/
- (void)insertNewEntity:(NSDictionary *)dict success:(void(^)(void))success fail:(void(^)(NSError *error))fail;
/**
查詢數(shù)據(jù)
@param selectKays 數(shù)組高級排序(數(shù)組里存放實(shí)體中的key般甲,順序按自己需要的先后存放即可)肋乍,實(shí)體key來排序
@param isAscending 升序降序
@param filterString 查詢條件
@param filterString 成功回調(diào)
@param fail 失敗回調(diào)
*/
- (void)selectEntity:(NSArray *)selectKays ascending:(BOOL)isAscending filterString:(NSString *)filterString success:(void(^)(NSArray *results))success fail:(void(^)(NSError *error))fail;
/**
刪除數(shù)據(jù)
@param model NSManagedObject
@param success 成功回調(diào)
@param fail 失敗回調(diào)
*/
- (void)deleteEntity:(NSManagedObject *)model success:(void(^)(void))success fail:(void(^)(NSError *error))fail;
/**
更新數(shù)據(jù)
@param success 成功回調(diào)
@param fail 失敗回調(diào)
*/
- (void)updateEntity:(void(^)(void))success fail:(void(^)(NSError *error))fail;
@end
CoreDataManager.m
#import "CoreDataManager.h"
//獲取CoreData的.xcdatamodel文件的名稱
static NSString * const coreDataModelName = @"CoreDataText";
//獲取CodeData
static NSString * const coreDataEntityName = @"CoreDataMode";
//數(shù)據(jù)庫
static NSString * const sqliteName = @"CoreDataMode.sqlite";
@interface CoreDataManager()
@end
@implementation CoreDataManager
@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
static CoreDataManager *coreDataManager = nil;
+ (instancetype)sharedInstance
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
coreDataManager = [[CoreDataManager alloc] init];
});
return coreDataManager;
}
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (coreDataManager == nil) {
coreDataManager = [super allocWithZone:zone];
}
});
return coreDataManager;
}
- (void)insertNewEntity:(NSDictionary *)dict success:(void (^)(void))success fail:(void (^)(NSError *))fail {
if (!dict||dict.allKeys.count == 0) return;
// 通過傳入上下文和實(shí)體名稱,創(chuàng)建一個(gè)名稱對應(yīng)的實(shí)體對象(相當(dāng)于數(shù)據(jù)庫一組數(shù)據(jù)敷存,其中含有多個(gè)字段)
NSManagedObject * entity = [NSEntityDescription insertNewObjectForEntityForName:coreDataEntityName inManagedObjectContext:self.managedObjectContext];
// 實(shí)體對象存儲(chǔ)屬性值(相當(dāng)于數(shù)據(jù)庫中將一個(gè)值存入對應(yīng)字段)
for (NSString *key in [dict allKeys]) {
[entity setValue:[dict objectForKey:key] forKey:key];
}
// 保存信息墓造,同步數(shù)據(jù)
NSError *error = nil;
BOOL result = [self.managedObjectContext save:&error];
if (!result) {
NSLog(@"添加數(shù)據(jù)失敗:%@",error);
if (fail) {
fail(error);
}
} else {
NSLog(@"添加數(shù)據(jù)成功");
if (success) {
success();
}
}
}
- (void)deleteEntity:(NSManagedObject *)model success:(void (^)(void))success fail:(void (^)(NSError *))fail {
// 傳入需要?jiǎng)h除的實(shí)體對象
[self.managedObjectContext deleteObject:model];
// 同步到數(shù)據(jù)庫
NSError *error = nil;
[self.managedObjectContext save:&error];
if (error) {
NSLog(@"刪除失斆场:%@",error);
if (fail) {
fail(error);
}
} else {
NSLog(@"刪除成功");
if (success) {
success();
}
}
}
- (void)selectEntity:(NSArray *)selectKays ascending:(BOOL)isAscending filterString:(NSString *)filterString success:(void (^)(NSArray *))success fail:(void (^)(NSError *))fail {
// 1.初始化一個(gè)查詢請求
NSFetchRequest *request = [[NSFetchRequest alloc] init];
// 2.設(shè)置要查詢的實(shí)體
NSEntityDescription *desc = [NSEntityDescription entityForName:coreDataEntityName inManagedObjectContext:self.managedObjectContext];
request.entity = desc;
// 3.設(shè)置查詢結(jié)果排序
if (selectKays&&selectKays.count>0) { // 如果進(jìn)行了設(shè)置排序
NSMutableArray *array = [NSMutableArray array];
for (NSString *key in selectKays) {
/**
* 設(shè)置查詢結(jié)果排序
* sequenceKey:根據(jù)某個(gè)屬性(相當(dāng)于數(shù)據(jù)庫某個(gè)字段)來排序
* isAscending:是否升序
*/
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:key ascending:isAscending];
[array addObject:sort];
}
if (array.count>0) {
request.sortDescriptors = array;// 可以添加多個(gè)排序描述器觅闽,然后按順序放進(jìn)數(shù)組即可
}
}
// 4.設(shè)置條件過濾
if (filterString) { // 如果設(shè)置了過濾語句
NSPredicate *predicate = [NSPredicate predicateWithFormat:filterString];
request.predicate = predicate;
}
// 5.執(zhí)行請求
NSError *error = nil;
NSArray *objs = [self.managedObjectContext executeFetchRequest:request error:&error]; // 獲得查詢數(shù)據(jù)數(shù)據(jù)集合
if (error) {
NSLog(@"失敗");
if (fail) {
fail(error);
}
} else{
NSLog(@"成功");
if (success) {
success(objs);
}
}
}
- (void)updateEntity:(void (^)(void))success fail:(void (^)(NSError *))fail {
NSError *error = nil;
[self.managedObjectContext save:&error];
if (error) {
NSLog(@"刪除失敗:%@",error);
if (fail) {
fail(error);
}
} else {
if (success) {
success();
}
}
}
#pragma 懶加載
//managedObjectModel 屬性的getter方法
-(NSManagedObjectModel *)managedObjectModel
{
if (_managedObjectModel != nil) return _managedObjectModel;
//.xcdatamodeld文件 編譯之后變成.momd文件 (.mom文件)
NSURL * modelURL = [[NSBundle mainBundle] URLForResource:coreDataModelName withExtension:@"momd"];
//把文件的內(nèi)容讀取到managedObjectModel中
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
//Coordinator 調(diào)度者負(fù)責(zé)數(shù)據(jù)庫的操作 創(chuàng)建數(shù)據(jù)庫 打開數(shù)據(jù) 增刪改查數(shù)據(jù)
-(NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) return _persistentStoreCoordinator;
//根據(jù)model創(chuàng)建了persistentStoreCoordinator
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
// 設(shè)置數(shù)據(jù)庫存放的路徑
NSURL * storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:sqliteName];
NSError * error = nil;
//如果沒有得到數(shù)據(jù)庫挽牢,程序崩潰
/*
持久化存儲(chǔ)庫的類型:
NSSQLiteStoreType SQLite數(shù)據(jù)庫
NSBinaryStoreType 二進(jìn)制平面文件
NSInMemoryStoreType 內(nèi)存庫,無法永久保存數(shù)據(jù)
雖然這3種類型的性能從速度上來說都差不多摊求,但從數(shù)據(jù)模型中保留下來的信息卻不一樣
在幾乎所有的情景中禽拔,都應(yīng)該采用默認(rèn)設(shè)置,使用SQLite作為持久化存儲(chǔ)庫
*/
// 添加一個(gè)持久化存儲(chǔ)庫并設(shè)置類型和路徑,NSSQLiteStoreType:SQLite作為存儲(chǔ)庫
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
{
if (error) {
NSLog(@"添加數(shù)據(jù)庫失敗:%@",error);
} else {
NSLog(@"添加數(shù)據(jù)庫成功");
}
NSLog(@"錯(cuò)誤信息: %@, %@", error, [error userInfo]);
}
return _persistentStoreCoordinator;
}
-(NSURL *)applicationDocumentsDirectory
{
//獲取沙盒路徑下documents文件夾的路徑 NSURL (類似于search)
NSLog(@"%@",[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject].absoluteString);
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
//容器類 存放OC的對象
-(NSManagedObjectContext *)managedObjectContext
{
if (_managedObjectContext != nil) return _managedObjectContext;
NSPersistentStoreCoordinator * coordinator = [self persistentStoreCoordinator];
if (!coordinator)
{
return nil;
}
//創(chuàng)建context對象
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
//讓context和coordinator關(guān)聯(lián) context可以對數(shù)據(jù)進(jìn)行增刪改查功能 // 設(shè)置上下文所要關(guān)聯(lián)的持久化存儲(chǔ)庫
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
}
@end
6睹栖、具體使用
-
增 insert
NSDictionary * dict = @{@"title":@"title2",@"content":@"content2"}; [[CoreDataManager sharedInstance] insertNewEntity:dict success:^{ NSLog(@"成功"); } fail:^(NSError *error) { NSLog(@"失敗"); }];
運(yùn)行結(jié)果 :
2018-11-12 13:25:06.730756+0800 CoreDataText[1600:1182994] 添加數(shù)據(jù)成功
數(shù)據(jù)庫中顯示:
-
查詢 select
[[CoreDataManager sharedInstance] selectEntity:nil ascending:YES filterString:nil success:^(NSArray *results) { NSLog(@"數(shù)據(jù)---%@",results); } fail:^(NSError *error) { }];
運(yùn)行結(jié)果:
-
改 updata
[[CoreDataManager sharedInstance] selectEntity:nil ascending:YES filterString:nil success:^(NSArray *results) { NSLog(@"數(shù)據(jù)---%@",results); if (results.count>0) { //更新某個(gè) NSManagedObject * model = [results firstObject]; [model setValue:@"xiugaile title" forKey:@"title"]; [model setValue:@"xiugaile content" forKey:@"content"]; [[CoreDataManager sharedInstance] updateEntity:^{ } fail:^(NSError *error) { }]; } } fail:^(NSError *error) { }];
運(yùn)行結(jié)果 :
在這里插入圖片描述在這里插入圖片描述 -
刪除 delete
//刪除某個(gè) NSString * filterString = [NSString stringWithFormat:@"title = 'title'"]; [[CoreDataManager sharedInstance] selectEntity:nil ascending:YES filterString:filterString success:^(NSArray *results) { NSLog(@"數(shù)據(jù)---%@",results); if (results.count>0) { //刪除某個(gè) [[CoreDataManager sharedInstance] deleteEntity:[results firstObject] success:^{ } fail:^(NSError *error) { }]; } } fail:^(NSError *error) { }]; //全部刪除 [[CoreDataManager sharedInstance] selectEntity:nil ascending:YES filterString:nil success:^(NSArray *results) { NSLog(@"數(shù)據(jù)---%@",results); //全部刪除 for (NSManagedObject *obj in results){ [[CoreDataManager sharedInstance] deleteEntity:obj success:^{ } fail:^(NSError *error) { }]; } } fail:^(NSError *error) { }];
運(yùn)行結(jié)果:
在這里插入圖片描述在這里插入圖片描述
參考:
https://blog.csdn.net/u013983033/article/details/83378838
http://www.reibang.com/p/e98daf9fec78
http://www.reibang.com/p/332cba029b95
http://www.reibang.com/p/e676ade9fcc6
http://www.reibang.com/p/c640dc6fd0e0