Core Data是iOS5之後才出現的一個架構,它提供了對象-關系映射(ORM)的功能即能夠将OC對象轉化成資料,儲存在SQLite資料庫檔案中,也能夠将儲存在資料庫中的資料還原成OC對象。
傳統的資料庫要把資料寫到資料庫,而且要寫SQL語句 Core Data 就避免了寫SQL語句的麻煩了
CoreData底層的持久化存儲方式可以是SQLite資料庫,也可以是XML檔案,甚至可以直接以記憶體作為持久化儲存設備(如果選用該存儲方式,那麼應用重新開機時資料會丢失)。
CoreData的核心概念是實體。實體是由Core Data管理的模型對象,它必須是NSManagedObject類或其子類的執行個體。實體與實體之間存在1-1、1-N、N-N的關聯關系。整個應用的所有實體以及實體之間的關聯關系被稱為托管對象模型。
CoreData的核心對象是托管對象上下文(NSManagedObjectContext,有時簡稱上下文),所有實體都處于托管對象上下文管理中,Core Data應用對實體所做的任何增、删、改、查操作都必須通過托管對象上下文來完成。
NSManagedObjectContext底層又與持久化存儲協調器(NSPersistentStoreCoordinator)銜接。持久化存儲協調器負責管理底層的存儲形式,比如利用SQLite存儲。
下面來總結Core Data中的核心API:
1. 實體(NSManagedObject):代表實體。實體必須是該類或該類的子類
2. 托管對象模型(NSManagedObjectModel):該對象負責管理整個應用的所有實體以及實體之間的關聯關系。
3. 持久化存儲協調器(NSpersistentStoreCoordinator):負責管理底層的存儲方式,如利用SQLite存儲。
4. 托管對象上下文(NSManagedObjectContext):對實體做的增、删、改、查操作都必須通過托管對象上下文來完成。
5. 實體描述(NSEntityDescription):該對象代表了關于某個實體的描述資訊。從某種角度來說,該對象相當于實體的抽象。
6. 擷取請求(NSfetchRequest):該對象封裝了查詢實體的請求,包括程式需要查詢哪些實體、查詢條件、排序規則等。
下面介紹一下使用Core Data的步驟:
1. 建立NSManageObjectModel對象來加載管理應用的托管對象模型。
2. 以NSManageObjectModel對象為基礎,根據實際建立NSPersistentStoreCoordinator對象,該對象确定Core Data的底層存儲形式。
3. 以NSManageObjectModel對象為基礎,建立NSmanagedObjectContext對象,該對象是Core Data進行持久化通路的核心對象。
4. 利用擷取執行個體(NSFectRequest)再調用NSmanagedObjectContext的executeFetchRequest:error:方法執行查詢,找到符合條件的實體,再進行執行增、删、改、查操作,然後調用NSmanagedObjectContext對象的save:方法将修改白村到底層儲存設備。
下面我們還是來通過存儲學生資訊為例,來講解CoreData的簡單使用。
建立項目,勾選Use Core Data複選框,我這裡的項目名為:01-CoreData
create之後,會在項目導航區看到下圖檔案
還會在appDelegate類中發現多了幾個屬性和方法,如下:
appDelegate.h
#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
/**
* 托管對象上下文
*/
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
/**
* 托管對象模型
*/
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
/**
* 持久化存儲協調器
*/
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
/**
* 儲存上下文修改
*/
- (void)saveContext;
/**
* 擷取Document的URL路徑
*/
- (NSURL *)applicationDocumentsDirectory;
@end
appDelegate.m
#pragma mark - Core Data stack
@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
/**
* 擷取Document的URL路徑
*/
- (NSURL *)applicationDocumentsDirectory {
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
/**
* 初始化托管對象模型(實體以及實體之間的關聯關系)
*/
- (NSManagedObjectModel *)managedObjectModel {
if (_managedObjectModel != nil) {
return _managedObjectModel;
}
// 擷取實體模型檔案對應的URL
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"_1_CoreData" withExtension:@"momd"];
// 根據URL建立并初始化托管模型對象
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
/**
* 初始化持久化存儲協調器(Core Data底層的存儲形式)
*/
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
// 以托管模型對象建立并初始化協調器
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
// 擷取SQlLite資料庫的存儲目錄
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"_1_CoreData.sqlite"];
NSError *error = nil;
NSString *failureReason = @"There was an error creating or loading the application's saved data.";
// 設定底層資料存儲機制為SQLite資料庫,如果設定失敗則傳回錯誤資訊
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
// Report any error we got.(設定錯誤資訊)
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data";
dict[NSLocalizedFailureReasonErrorKey] = failureReason;
dict[NSUnderlyingErrorKey] = error;
error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
/**
* 初始化托管對象上下文
*/
- (NSManagedObjectContext *)managedObjectContext {
if (_managedObjectContext != nil) {
return _managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
return nil;
}
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
}
#pragma mark - Core Data Saving support
/**
* 儲存上下文的修改
*/
- (void)saveContext {
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
NSError *error = nil;
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
}
并且在應用的代理方法中有:(當應用退出後,會儲存上下文的修改)
- (void)applicationWillTerminate:(UIApplication *)application {
// Saves changes in the application's managed object context before the application terminates.
[self saveContext];
}
點選.xcodemodeld檔案,在工作區會出現如圖所示界面
點選左下角add Entity按鈕添加實體
然後在ENTITIES區會出現如圖所示實體,再重命名實體名,我這裡重命名為:StudentEntity
在該實體的右側會出現添加屬性界面,點選添加屬性
屬性添加完之後,點選xcode導航欄上的Editor -> Create NSManageObject Subclass自動建立實體類,如下:
這些準備工作做好以後,我們就可以向資料庫_1_CoreData.sqlite中進行資料的增、删、該、查操作了。
添加學生資訊:
點選添加按鈕,将學生資訊插入資料庫中(這裡不考慮重複插入)
/**
* 添加學生資訊
*/
- (IBAction)addClick {
// 利用NSEntityDescription擷取StudentEntity實體
StudentEntity *stu = [NSEntityDescription insertNewObjectForEntityForName:@"StudentEntity" inManagedObjectContext:[AppDelegate shareAppDelegate].managedObjectContext];
stu.name = self.nameTextField.text;
stu.age = [NSNumber numberWithInteger:[self.ageTextField.text integerValue]];
stu.sex = [NSNumber numberWithInt:[self.sexTextField.text intValue]];
NSError *error = nil;
[[AppDelegate shareAppDelegate].managedObjectContext save:&error];
if (error) {
NSLog(@"添加失敗");
}else {
NSLog(@"添加成功");
}
}
點選添加按鈕後,會在應用沙盒中發現下圖檔案:
列印結果:
現在我們向資料庫中多插入幾條資料,然後來做查詢操作,看看資料庫中有沒有資料。查詢操作如下:
/**
* 查詢所有學生資訊,并列印
*/
- (IBAction)queryClick {
// 得到擷取資料的請求對象
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"StudentEntity"];
// 排序規則(查詢結果按年齡降序排序)
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:NO];
request.sortDescriptors = @[sort];
// 執行查詢
NSError *error = nil;// 錯誤資訊
NSArray *result = [[AppDelegate shareAppDelegate].managedObjectContext executeFetchRequest:request error:&error];
if (error) {
NSLog(@"查詢操作失敗");
}else {
if (result.count <= 0) {
NSLog(@"無學習資訊");
}else {
NSLog(@"列印學生資訊:");
for (StudentEntity *stu in result) {
NSLog(@"姓名:%@,年齡:%lu,性别:%d", stu.name, stu.age.integerValue, stu.sex.intValue);
}
}
}
}
列印出來看看,我們剛剛添加的多條學生資訊
結果就是我們添加的學生,證明我們的資料已經添加到資料庫中了。
我們先來删除指定姓名(如:shx1)的學生資訊:(資料庫中所有叫shx1的學生會全部删除)
/**
* 删除指定姓名的學生資訊
*/
- (IBAction)deleteClick {
// 先周遊資料庫,查詢有無該學生資訊,無該學生則不用執行删除操作
// 得到擷取資料的請求對象
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"StudentEntity"];
// 查詢條件
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name = %@", self.deleteNameTextField.text];
request.predicate = predicate;
// 排序規則(按年齡升序)
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:NO];
request.sortDescriptors = @[sort];
// 執行查詢
NSError *error = nil;// 錯誤資訊
NSArray *result = [[AppDelegate shareAppDelegate].managedObjectContext executeFetchRequest:request error:&error];
// 查詢結果
if (error) {
NSLog(@"查詢操作失敗");
}else {
if (result.count) {// 有該學生資訊,可執行删除操作
for (StudentEntity *stu in result) {
// 删除學生資訊
[[AppDelegate shareAppDelegate].managedObjectContext deleteObject:stu];
NSLog(@"删除成功");
}
// 删除資料後,儲存
NSError *saveError = nil;
[[AppDelegate shareAppDelegate].managedObjectContext save:&saveError];
if (saveError) {
NSLog(@"删除,儲存失敗");
}else {
NSLog(@"删除,儲存成功");
}
}else {
NSLog(@"無該學生資訊");
}
}
}
輸入要删除的學生姓名:shx1列印結果:
我們再查詢所有學生資訊,并列印,看看shx1還在不在,點選查詢:
姓名叫shx1的學生沒有了,證明我們已經删除了。
現在我們來修改某個學生(比如:shx5)的年齡。(原shx5的年齡從上面指定為22,現在我們将他的年齡改為100,資料庫中所有叫shx5的學生的年齡都會被改成100)。
/**
* 修改某個學生的年齡
*/
- (IBAction)tureClick {
// 先周遊資料庫,查詢有無該學生資訊,無該學生則不能修改年齡
// 得到擷取資料的請求對象
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"StudentEntity"];
// 查詢條件
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name = %@", self.updateNameTextField.text];
request.predicate = predicate;
// 執行查詢
NSError *error = nil;// 錯誤資訊
NSArray *result = [[AppDelegate shareAppDelegate].managedObjectContext executeFetchRequest:request error:&error];
// 查詢結果
if (error) {
NSLog(@"查詢操作失敗");
}else {
if (result.count) {// 有該學生資訊,可執行修改操作
for (StudentEntity *stu in result) {
// 修改學生資訊
stu.age = [NSNumber numberWithInt:self.updateAgeTextField.text.intValue];
NSLog(@"修改成功");
}
// 删除資料後,儲存
NSError *saveError = nil;
[[AppDelegate shareAppDelegate].managedObjectContext save:&saveError];
if (saveError) {
NSLog(@"修改,儲存失敗");
}else {
NSLog(@"修改,儲存成功");
}
}else {
NSLog(@"無該學生資訊");
}
}
}
姓名輸入shx5,年齡輸入100,列印結果:
我們查詢所有的學生資訊,并列印出來,看看shx5的年齡是不是100。
姓名叫shx5的學生的年齡已經改為100了,證明我們的資料庫操作是正确的。
以上是關于Core Data的簡單使用,更進一步的使用我也在學習中。