什么是Core Data
简单来说,Core Data就是一个面向对象的持久化数据管理框架。使用Core Data可以将数据持久化的保存在存储设备中,也可以在适当的时候将其取出来。
Core Data底层的存储方式既可以是SQLite数据库也可以是XML文档甚至都可以将数据保存在内存中。
使用Core Data的好处是可以以面向对象的方式进行数据操作避免了直接与SQL语句接触,简化了操作步骤,提升程序开发效率。
Core Data的构成
1. NSManagedObject
Core Data 所管理的实体。
实体是Core Data的核心概念,其为Core Data所管理的对象。其中,实体必须为NSManagedObject或其子类。
实体有自己的属性,例如一个书籍的实体就可以有书名、价格、作者等属性。一个作者的实体就可以有姓名、出生年月、写过的书籍等属性。
实体之间的关系有1-1,1-N,N-N,例如一个书籍可以对应一个作者,这就是1-1关系,一个作者可以对应多本书籍,这就是N-N关系。
2. NSManagedObjectContext
托管对象上下文对象是Core Data中的核心对象,要对Core Data所管理的实体进行增、删、改、查都要通过此对象进行。
3. NSPersistentStoreCoordinator
持久化存储协调器对象负责Core Data的底层存储结构,对Core Data的底层的存储方式的初始化就要经过这个对象。例如,要使用SQLite方式存储NSManagedObject或其子类,就要经过这个对象来进行设置。
4. NSManagedObjectModel
托管对象模型对象包含了Core Data中的所有的NSManagedObject以及实体之间的关系。
它对应于项目中的.xcdatamodeld
文件(编译后为.momd
文件),可以用来以可视化的方式编辑Core Data中的各种实体以及关系。
5. NSEntityDescription
实体描述是对Core Data 中的实体进行抽象。
相当于数据库中的表结构。
6. NSFetchRequest
实体获取请求用来按特定条件获取Core Data中的数据。
可以想象成数据库中的查询语句。
应用实例
估计看了上面的一大堆也很难理解Core Data的组成及使用,下面通过一个小的应用实例来近距离感受下Core Data。
Core Data 中有两个实体,分别是LXYBook
和LXYAuthor
。
其中LXYBook
有name
与price
两个属性,LXYAuthor
有
name
与authorDesc
两个属性。
应用的界面架构如下:
第一行,从左到右依次是
Navigation Controller ->LXYAuthorListTableViewController->LXYBooksListTableViewController
第二行从左到右依次是
LXYUserAddNavigationController->LXYBooksAddNavigationController
第一行从左到右依次是
LXYUserAddNavigationController->LXYBooksAddNavigationController
第二行从左到右依次是
LXYAuthorAddViewController->LXYBookAddViewController
所有文件结构如下
其中,LXYBooksListTableViewController
用于显示某个作者的书籍列表,LXYAuthorListTableViewController
用于显示所有的作者。点击某个作者进入LXYBooksListTableViewController
。LXYAuthorAddViewController
用于添加作者,LXYBookAddViewController
用于添加指定作者的书籍。
1. 新建应用
新建一个iOS的Single View Application没什么好说的。
2. 添加Core Data支持
在Xcode中点击File->new file 点击左侧的Core Data,再选Data Model,如下图所示
点击Next,填好相应信息,如下图
我起的名字是 LXYBooksModel
,现在应该出现在项目的文件列表里面,我的情况如下图
3. 配置实体及关系
点击LXYBooksModel.scdatamodeld
文件,点击Add Entity 将Entity命名为LXYBook
,再点击Attributes
栏里的+
按钮,添加name、price属性并分别将属性类型配置为String
和Double
。再按相同步骤添加并配置好LXYAuthor实体及其属性,配置好如下图所示
再在LXYBook
的RelationShip栏中添加一个author
关系,并按下图配置好
同样的方式在LXYAuthor
中添加books
关系,并按下图配置好
最后点击Editor->Create NSManagedObject subclass 并勾选相应地实体生成与实体同名的子类。
4. 初始化Core Data框架
如下编辑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;
- (NSURL *) applicationDocumentDirectory;
@end
在AppDelegate.m
文件中首先将与Core Date有关的三个属性设置为@synsize
,再分别设置他们的get方法,实现Lazy Loading
@synthesize managedObjectContext = _managedObjectContext;
@synthesize managedObjectModel = _managedObjectModel;
@synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
- (NSManagedObjectContext *)managedObjectContext
{
if(_managedObjectContext != nil)
{
return _managedObjectContext;
}
//获取NSPersistentStoreCoordinator对象
NSPersistentStoreCoordinator * persistentStoreCoordinator = self.persistentStoreCoordinator;
if(persistentStoreCoordinator != nil)
{
_managedObjectContext = [[NSManagedObjectContext alloc] init];
//根据NSPersistentStoreCoordinator设置
//NSManagedObjectContext的底层存储方式
[_managedObjectContext setPersistentStoreCoordinator:persistentStoreCoordinator];
}
return _managedObjectContext;
}
- (NSManagedObjectModel *)managedObjectModel
{
if(_managedObjectModel != nil)
{
return _managedObjectModel;
}
//根据LXYBooksModel.xcdatamodeld文件
//(编译后为LXYBooksModel.momd文件)
//初始化NSManagedObjectModel
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"LXYBooksModel" withExtension:@"momd"];
_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
//初始化并设置为SQLLite数据库方式存储数据
NSURL *storeURL = [[self applicationDocumentDirectory] URLByAppendingPathComponent:@"LXYBooks.sqlite"];
NSError *error = nil;
NSString *failureReason = @"There was an error creating or loading the application's saved data.";
//如果不能正确初始化
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
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;
}
//保存数据
- (void)saveContext
{
NSError * error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if(managedObjectContext != nil)
{
//检测是否有数据变化并且还未保存
//如果有就保存
//保存失败报告原因
if([managedObjectContext hasChanges] && ![managedObjectContext save:&error])
{
NSLog(@"saved failed: %@,%@",error,[error userInfo]);
abort();
}
}
}
//获取用户沙箱路径用于创建数据库文件
- (NSURL *)applicationDocumentDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
//应用将要结束时调用saveContext方法保存数据
- (void)applicationWillTerminate:(UIApplication *)application {
[self saveContext];
}
5. 其他文件代码
在LXYAuthorListTableViewController
中获取全部作者
- (NSMutableArray *)fetchAuthorsFromDataSource
{
NSFetchRequest *request = [[NSFetchRequest alloc] init];
//设置实体描述
NSEntityDescription *entity = [NSEntityDescription entityForName:@"LXYAuthor" inManagedObjectContext:self.appDelegate.managedObjectContext];
[request setEntity:entity];
NSError *error = nil;
//执行获取语句
NSMutableArray *authors = [[self.appDelegate.managedObjectContext
executeFetchRequest:request error:&error] mutableCopy];
if(authors == nil)
{
NSLog(@"Error when fetch authors from data source:%@,%@",error,[error userInfo]);
}
return authors;
}
从Core Data中删除作者
//从Core Data中删除传入的LXYAuthor
- (void)removeAuthorFromDataSource:(LXYAuthor *)author
{
[self.appDelegate.managedObjectContext deleteObject:author];
NSError *error = nil;
if(![self.appDelegate.managedObjectContext save:&error])
{
NSLog(@"Error when remove author form data source:%@,%@",error,[error userInfo]);
}
}
在LXYAuthorAddViewController
中添加作者
- (void)addAuthor
{
NSString *name = self.nameTextField.text;
NSString *authorDesc = self.descTextField.text;
//在Core Data中创建LXYAuthor对象
LXYAuthor *author = [NSEntityDescription insertNewObjectForEntityForName:@"LXYAuthor" inManagedObjectContext:self.appDelegate.managedObjectContext];
//设置属性
author.name = name;
author.authorDesc = authorDesc;
NSError *error = nil;
//执行保存并验证是否保存成功
if([self.appDelegate.managedObjectContext save:&error])
{
NSLog(@"Error when add author:%@,%@",error,[error userInfo]);
}
}
在LXYBooksListTableViewController
中获取指定作者的书籍
- (NSMutableArray *)fetchBooksForAuthor:(LXYAuthor *)author
{
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"LXYBook" inManagedObjectContext:self.appDelegate.managedObjectContext];
[request setEntity:entity];
//设置request的谓词,相当于SQL语句中的
//WHERE author = ? 子句
//用于获取指定作者的书籍
//这里就是根据在Core Data中的LXYBook实体的author关系来抓取
request.predicate = [NSPredicate predicateWithFormat:@"author=%@",author];
NSError *error = nil;
NSMutableArray *books = [[self.appDelegate.managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
if(books == nil)
{
NSLog(@"Error when fetch books for author:%@,%@",error,[error userInfo]);
}
return books;
}
在LXYBookAddViewController
中添加指定作者的书籍
- (void)addBookForAuthor:(LXYAuthor *)author
{
LXYBook *book = [NSEntityDescription insertNewObjectForEntityForName:@"LXYBook" inManagedObjectContext:self.appDelegate.managedObjectContext];
book.name = self.nameTextField.text;
double price = [self.priceTextField.text doubleValue];
book.price = [NSNumber numberWithDouble:price];
//这里直接设置即可
//关系也可以当做属性使用
book.author = self.author;
NSLog(@"In books add ,author name:%@",book.author);
NSError *error = nil;
if(![self.appDelegate.managedObjectContext save:&error])
{
NSLog(@"Error when add book for author:%@,%@",error,[error userInfo]);
}
else
{
NSLog(@"Add book successed");
}
}
完整程序见 我的GitHub