斯坦福大学iOS公开课笔记(12)-CoreData

这一节课主要是介绍iOS中本地化处理最有力的工具,CoreData。这节课中主要是介绍CoreData的概念部分,在下节课中会做一个大的Demo,用来展示如何使用CoreData进行数据的本地化处理。

CoreData是一个本地数据化的工具,但是他不是一个数据库,而是作为一个链接类和数据库之间的桥梁,在通过使用CoreData中的一些方法可以实现对数据库的增删改查的方法。

创建一个CoreData文件

  • 在创建项目的时候创建CoreData。

    在创建一个项目的时候,我们可以勾选Core Data来创建一个CoreData文件

    logo
  • 在已有项目中创建一个CoreData

    通过点击 cmd+n 或者File -> New -> File… 。

    logo

    然后选择 CoreData 中的 Data Model。

    logo

    之后就会生成一个后缀为.xcdatamodeld的CoreData文件。

    这其中有:

    • Entity(实体):对应数据库中的表。
    • Attribute (属性):对应数据库中的列。
    • Relationships (关系):链接不同表格的作用
    • Fetched Properties (取回属性)。

NSManagedObjectContext

NSManagedObjectContext 就是作为类和数据库链接的关键,所有的增删改查操作都需要依赖于他,创建NSManagedObjectContext有两种方式:

  • 第一种是通过 UIManagedDocument来管理,这里主要讲的是这种方法;
  • 另一种是通过 alloc init 来生成。

创建UIManagedDocument

首先我们创建一个URL,这个URL用来存储CoreData。

1
2
3
4
5
6
7
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *documentsDirectory = [[fileMagager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject];
NSString *documentName = @"MyDocument";
NSURL *url = [documentDirectory URLByAppendingPathComponent:documentName];
//提供一个URL,这个URL是存储CoreData的地方
UIManagedDocument *document = [[UIManagedDocument alloc] initWithFileURL:url];

创建了UIManagedDocument之后并不代表它已经存在在磁盘上了,所以我们需要做一些操作,让他可以保存在磁盘上。

1
2
3
4
5
6
7
8
9
10
11
12
BOOL fileExists = [[NSFileManager defaultManger] fileExiststAtPath:[url path]];
//如果文件已存在,就打开这个文件。
if(fileExists)
{
[document openWithCompletionHandler:^(BOOL success){ }];
}
//如果文件不存在,就保存。
else
{
[document saveToURL:url forSaveOperation:UIDocumentSaveForCreating competionHandler:^(BOOL success){ }];
}

文档状态

当UIManagedDocument创建或者打开之后,我们可以通过检查文档状态来判断当前文档是否可用,如果不可用需要等一下再试或者排查一下错误。

1
2
3
4
if(self.document.documentState == UIDocumentStateNormal)
{
//开始操作文档
}

这里还有一些其他的状态:

1
2
3
4
5
UIDocumentStateNormal //正常状态
UIDocumentStateClosed //关闭,还没有打开或者还没有创建
UIDocumentStateSavingError //保存错误
UIDocumentStateEditingDisabled //编辑暂时禁用
UIDocumentStateInConflict //可能是iCloud中有其他人正在编辑这个文档

从UIManagedDocument中获取NSManagedObjectContext

当我们创建完UIManagedDocument并判断他是正常状态之后,我们就可以通过UIManagedDocument来获取NSManagedObjectContext,然后做一些Core Data相关的操作了。

1
NSManagedObjectContext *context = self.document.managedObjectContext;

需要注意的点

    1. UIManagedDocument是自动存储的,并且是异步执行的,存储的方法我们可以调用,但是通常我们都让他自动存储。
1
2
3
[document saveToURL:document.fileURL forSaveOperation:UIDocumentSaveOverwriting compertionHandler:^(BOOL success){
}];
    1. UIMangedDocument是自动关闭的,同样也是异步执行的,当没有强指针指向他的时候,他就会自动关闭。当然我们也可以手动调用关闭,但是通常我们让他自动关闭。
1
2
3
[document closeWithCompletionHandler:^(BOOL success){
}];
    1. 使用通知来获取文档是否被保存
1
2
3
4
[center addObserver:self
selector:@selector(contextChanged:)
name:NSManagedObjectContextDidSaveNotification
object:document.managedObjectContext]; //这里记得不要传nil

为属性创建子类

ok,现在我们有了NSManagedObjectContext,接下来我们需要对数据进行操作,在操作之前我们还要做一个步骤,如果我们现在对数据进行操作的话就必须使用KVO,根据key值来对数据进行修改,这样既不方便,也不安全,一个不小心就会照成崩溃。所以如何解决这个问题,就需要为属性创建子类来帮助我们管理数据。

我们可以通过 Editor -> Create NSManagedObjectContext Subclass -> 然后选择你要创建子类的属性,然后一路next下去。

logo

这里要注意一点:在Xcode8下,通过这个步骤下来可能会出现报错,这个时候我们先把Codegen改成Manual/none,在按照上边的步骤操作一遍就可以了。

logo

通过创建了子类之后,我们就可以直接使用点语法来对数据进行操作,大大提高了代码的可读性和编写效率,同时也降低了代码的崩溃风险。

Core Data数据的操作

接下来,我们终于可以对数据进行操作了。因为下节课是一个针对Core Data的很大的Demo,所以数据的操作这方面这节课就不仔细写出来了,具体的实现可以看下节课Demo中的代码。

添加操作

添加操作只需要一行代码,这里的name就是实体类的名称,context就是NSManagedContext。

1
2
[NSEntityDescription insertNewObjectForEntiyForName:@"Photo"
inManagedObjectContext:context];

删除操作

1
[aDocument.managedObjectContext deleteObject:photo];

执行了删除操作之后,会发生消息 prepareForDeletion给所有的对象

1
2
3
4
- (void)prepareForDeletion
{
}

查询操作

查询操作主要通过 NSFetchRequest来实现。通过它我们也可以对请求进行分页处理,添加一些筛选条件等等。

1
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Photo"];

更多的CoreData的应用会在下节课的Demo中用到,所以这里就不在过多的进行介绍了。