Core Data是iOS编程中使用持久化数据存储的一种方式。在以前的教程 – ,我们已经提供了三种方式来实现App数据的存储,分别为:
(1) 用户默认设置 – 这种情况通常不需要用户干预,如游戏通关信息,Video播放记录,或者App退出之后,下次进入时,希望恢复到退出时的情况。
(2) 设置束(Settings Bundle)– 提供了一个通过iPhone、iPad的设置(Settings)应用程序进行配置的接口。(3) 直接访问文件系统 – 读写属于当前App的iOS 文件系统部分的文件。在一些情况下,我们可以考试使用Core Data来持久化数据。需要知道的是,Core Data 并不是数据库本身,是Apple提供的对象持久化技术(Object Persistent Technology)。Core Data 框架为数据变更管理、对象存储、对象读取恢复的功能提供了支持。它可以使用SQLite作为持久化存储的类型,但本身并不是一个数据库。
教程将重点介绍和演示Core Data框架的使用,并不是创建一个完美的应用程序,而是演示基于Core Data框架创建应用程序的过程中,所需要使用到的一些基础类、工具和技术。
下面先了解Core Data框架提供的一些核心类,在App开发过程中需要使用到。
Core Data 堆栈(Stack)
堆栈(Stock)术语用来表述Core Data框架对象集合,这些对象实现从模型对象中获取数据,和保存数据到持久化存储(Persistent Store)中-也就是数据文件。从概念上讲,一个持久化存储(Persistent Store)就像一个数据库,有数据表和数据记录。我们可选用的Core Data存储类型之一是SQLite,但是存储文件并不一定是实际的数据库。
下图是一个简单的、且常用的Core Data堆栈配置。我们通常直接使用的类是堆栈顶部的Managed Object Context(被管理对象上下文)和它所包含的Managed Objects(被管理对象)。
被管理对象和被管理对象上下文
被管理对象(Managed Object)是NSManagedObject对象或NSManagedObject子类对象实例。其实,也就是数据库中数据表记录的对象表示,由Core Data管理的模型(Model)对象。被管理对象(Managed Object)表示应用程序中操作的数据,例如人力资源应用系统中的部门和员工;画图应用程序中的各类形状、文本等等。一个被管理对象总是和一个被管理对象上下文(Managed Object Context)相关联。
被管理对象上下文(Managed Object Context)是NSManagedObjectContext对象实例。上下文表示应用程序中的一个单一对象空间,它的主要职责管理被管理对象(Managed Object)集合。这些对象组成了一组关联的模型对象(Model Object),描绘了一个或多个持久化存储(Persistent Store)。上下文(Context)是非常强大的对象,在应用程序中起到中心作用,负责生命周期管理到验证、关系维护(Relationship Maintenance)和撤销/重做特性。
在我们创建一个新的被管理对象时,将它插入到Context中。从数据库中获取的现存记录也将放到Context中,作为被管理对象。所有对被管理对象(Managed Object)的修改都保留在内存中,直到正在提交给持久化存储保存上下文(Context)。
下图描绘了被管理对象上下文(Managed Object Context)包含2个被管理对象(Managed Object),对应着数据库中2条记录。其中一个对象的属性值已经在内存中更新过了,但还没有提交到数据库保存。另外,还有2条记录在数据库中,并没有对应的被管理对象(Managed Object)。
被管理对象模型(Managed Object Model)
被管理对象模型是NSManagedObjectModel实例。被管理对象模型是数据库Schema的对象表示,是实体描述对象(Entity Description Object – NSEntityDescription实例)的集合。
一个实体描述对象(Entity Description Object)描述了数据库中一个数据表实体,包括表名称、表对应的被管理对象的名称、属性(Attributes)和关系(Relationships)等等。
下图描绘了实体描述对象、数据库中数据表和被管理对象(对应数据库表的一条记录)之间的关系。
从上图可以看出,每一个被管理对象(Managed Object)都有对应实体对象的引用。
Core Data使用模型(Model)来映射应用程序中被管理对象和数据库中的数据记录。需要注意的是,如果我们修改数据库的Schema,Core Data将无法使用之前创建的模型来读取数据库记录了。很多持久化机制都存在这个问题。我们一起看看下面这些示例代码:
Customer *customer1 = (Customer *)[NSEntityDescription insertNewObjectForEntityForName:@"Customer"inManagedObjectContext:self.managedObjectContext];customer1.customerID = [NSNumber numberWithInt:1];customer1.customerName = @"EntLib.com";customer1.password = @"EntLib.com";customer1.userName = @"EntLib.com";
Customer 类是NSManagedObject子类,NSEntityDescription insertNewObjectForEntityForName:inManagedObjectContext:方法创建customer1 被管理实体对象,并和被管理对象上下文(Managed Object Context)self.managedObjectContext相关联。
持久化存储协调器(Persistent Store Coordinator)
持久化存储协调器(Persistent Store Coordinator)在Core Data管理数据过程中扮演重要的角色,然而,在使用Core Data框架时,我们通常不必直接和协调器交互。这里我们详细介绍持久化存储协调器,如果你对此没有兴趣,可以跳过去。
持久化存储协调器是NSPersistentStoreCoordinator实例,管理持久化对象存储(Persistent Object Store)集合。一个持久化对象存储表示一个外部存储文件。
下图描绘了协调器扮演的作用。不过,一般iOS 应用程序中,我们通常使用单一存储(也就是一个数据库文件),因此Core Data堆栈并不会像下图这么复杂。
下面一段代码涉及到持久化存储协调器(Persistent Store Coordinator)的应用,创建持久化存储协调器(Persistent Store Coordinator)对象实例,并设置被管理对象上下文(Managed Object Context)的持久化存储协调器(Persistent Store Coordinator)。
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectoryinDomains:NSUserDomainMask] lastObject];NSURL *storeDatabaseURL = [url URLByAppendingPathComponent:@"ShoppingCart Database"];// url is now <Document Directory>/ShoppingCart DatabaseNSError *error = nil;NSPersistentStoreCoordinator *persistentStoreCoordinator =[[NSPersistentStoreCoordinator alloc]initWithManagedObjectModel:[NSManagedObjectModel mergedModelFromBundles:nil]];if(![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreTypeconfiguration:nilURL:storeDatabaseURL options:nil error:&error]){ NSLog(@"Error while loading persistent store ...%@", error);}
_managedObjectContext = [[NSManagedObjectContext alloc] init];[_managedObjectContext setPersistentStoreCoordinator:persistentStoreCoordinator];