前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >「死磕」Core Data——入门

「死磕」Core Data——入门

作者头像
iOS Development
发布2019-02-14 17:58:02
1.1K0
发布2019-02-14 17:58:02
举报
文章被收录于专栏:Antony iOS Development

适读对象:

  • 需要入门Core Data的朋友;
  • 像我一样,尚未学过数据库相关课程,不太懂怎么写SQLite语句的朋友;
  • 想了解一个文科狗理解、学习Core Data心路历程的朋友~

Core Data,iOS中一种保存和读取数据的机制。以学习曲线陡峭而闻名~

因为我是文科狗转行的程序猿,并没有学过数据库相关课程,也欣赏不出SQLite的美,所以之前的项目一直用NSKeyedArchiverNSKeyedUnarchiver(固化)进行数据的本地保存(所幸我接触的项目,数据都不会太复杂)。

其实一开始接触iOS开发,就有阅读过Core Data相关内容。不过一来当时水平太低,看不太懂;二来Core Data本来也难学;三来经手的项目也没有强制使用Core Data;四来国内使用Core Data的开发者也不占主流。所以花了很长很长一段时间才入了门。过程算是曲折,所以标题哗众取宠地用了「死磕」二字。

「太长不看版」

本文确实比较长(从侧面印证Core Data内容确实多),所以这里写一个「太长不看版」,「以飨读者」:

Core Data使用流程:

  • 创建Core Data Stack
  • iOS10中利用NSPersistentContainer
  • iOS10之前涉及NSManagedObjectContextNSPersistentStoreCoordinatorNSManagedObjectModelNSPersistentStore这些类
  • 创建模型文件(.xcdatamodel文件)
  • 按需增加「实体」、实体的「特性」、「关系」(如有需要)
  • 创建NSManagedObject子类(如有需要)

备注:如果创建项目时勾选了「Use Core Data」,会自动帮你创建好上述这些内容。

  • 增删查改:
  • :利用NSEntityDescription的类方法insertNewObjectForEntityForName:inManagedObjectContext:,添加数据(对象)
  • :利用NSManagedObjectContextdeleteObject:方法删除数据
  • :利用NSManagedObjectContextexecuteFetchRequest:error:方法,查询数据
  • 保存:利用NSManagedObjectContextsave:方法保存数据。

OK,基本上就是这些东西了~

术语

CoreData学习曲线陡峭的原因之一,术语太多算一个。所以这里整理一下,如下:

iOS Core Data 示意图

Core Data Stack

感觉理解起来有点抽象,先看官方定义:

The Core Data stack is a collection of framework objects that are accessed as part of the initialization of Core Data and that mediate between the objects in your application and external data stores.

说是一个对象的集合,由4个主要对象构成:

  • 「managed object context」 (NSManagedObjectContext),
  • 「persistent store coordinator」 (NSPersistentStoreCoordinator),
  • 「managed object model」 (NSManagedObjectModel),
  • 「persistent container」 (NSPersistentContainer).

我是这样理解的:Core Data Stack,就是进行数据增删查改、保存的「工作台」,Apple提供这样一个「工作台」,让你方便进行数据的保存。无需关心实现细节。

对应示意图第1个框框。

Persistent Container

NSPersistentContainer是iOS 10、 macOS 10.12之后才出现的新类。引入这个新类的目的之一,就是为了简化创建Core Data Stack这个工作台的过程。所以,在iOS10之前,创建Core Data Stack会复杂一些。

而Persistent Container也有另一个新类NSPersistentStoreDescription,可以利用这个类,进行一些定制化设置,比如自定义存储路径、设置存储数据方式等(Core Data支持SQLite、XML、Binary、InMemory 4中方式存储数据)。

备注:iOS10中,如果利用NSPersistentContainer创建Core Data Stack,预设的是NSSQLiteStoreType类型。并且默认打开了自动轻量化版本迁移功能(换言之,在iOS10之前,需要手动进行相关设置,才能打开版本迁移功能)。

对应示意图第2个虚线框框。

Managed Object Context。

可以理解为是一块内存,提供了和Managed Objects交互的场所。也称为:The Context或者MOC。NSManagedObjectContext类实例。

备注:对数据进行删除、保存、查询,都要用到NSManagedObjectContext类的相关方法。

对应示意图第3个框框。

Managed Object Model

直观点,你可以把它理解为就是Xcode中后缀为xcdatamodel的文件。在这个文件里,你可以通过非代码、可视化的方式,定义对象、对象的属性、对象之间的关系(Core Data把对象称呼为「实体」、对象的属性称呼为「特性」)。

Managed Object Model,就是Core Data中用于描述实体、实体特性、实体间关系的一套方案。

它是NSManagenObjectModel的类实例(也可以通过纯代码实现.xcdatamodel文件的内容)。也称为:The Model, Data Model, Schema或Object Graph。

换言之,Managed Object Model定义了你App的整个数据结构。

下面3个,是在设置.xcdatamodel文件时会遇到的3个术语。

  • Entity /「实体」

NSEntityDescription类实例,用于定义一个对象。一个「实体」,最少要有「名字」和「类名」(如果没有设置类名,默认是NSManagedObject类)。

  • Attribute / 特性

「实体特性」。NSAttributeDescription类实例。就是Entity的特性,对应App中的创建类时的属性。

  • Relationship / 关系

「实体关系」。 NSRelationshipDescription类实例。用于描述Entity之间的关系。

对应示意图第4个框框。

Managed Object。

就是需要保存的数据,是NSManagenObject类实例。(对应App中的「对象」)

就我的理解,Managed Object和上面提到的Entity,本质上是同一个东西,就是你的数据对象,只不过是在可视化操作和纯代码操作中的不同称谓。

对应示意图第5的那些框框。

Persistent Store Coordinator

协调Context和Persistent Store的一个角色。NSPersistentStoreCoordinator类实例。

如果只是对数据进行简单的增删查改,我们并不需要接触到这个类。

对应示意图第6个框框。

Persistent Store

可以理解为保存数据的地方。用于设置保存数据的方式、以及保存的路径等。(保存数据的方式指SQLite、XML、Binary、InMemory4种)。NSPersistentStore类实例。也称为The Store或者Database。

在iOS10之前,如果需要支持版本迁移功能,需要在创建NSPersistentStore类实例时,传入相应的options参数。而在iOS10中,则会自动打开版本迁移功能,并默认设置数据类型为NSSQLiteStoreType(见上面的名词:「NSPersistentStoreDescription」)。

「版本迁移」,一开始对这个名字很是迷惑,还以为是将数据模型从一个App迁移到另外一个App。其实,是在内部进行「迁移」。

简单说,假如修改了数据模型(比如修改了. xcdatamodel文件:增加了实体,增加了特性等等),为了防止使用者在更新App后,由于数据模型不一致导致崩溃,需要进行一定的处理,这个处理,他们叫「版本迁移」(叫「版本升级」不是更合适吗~)。

对应示意图第7个框框。

其他

  • Optional:「实体特性」的配置选项(勾选了之后,表示这个特征可为空nil)
  • Transient:「实体特性」的配置选项(勾选了之后,该属性不会保存到沙盒中)
  • Fetch Requset。描述了从Persistent Store中取回数据的方式方法。NSFetchRequest类实例。查询数据的时候会用到。
  • Preficate:又称为:Filter。描述了取回数据的过滤方式。(有人翻译为「断言」,有人翻译为「谓语」)。NSPredicate类实例。查询数据的时候会用到。
  • Stort Descriptor。描述了取回数据的排序方式。NSSortDescriptor类实例。也是查询数据的时候会用到。

可参考以下表格,对照进行理解(这个表格或许不慎严谨)

数据库术语

代码中的术语

Core Data中的术语

表格

实体 / Entity(NSEntityDescription类实例)

属性

实体特性(Attribute)

对象(类实例)

NSManagedObject(子)类实例

使用步骤

大部分教程是先创建「managed object model」,再初始化「Core Data Stack」的。因为我这里把「Core Data Stack」比喻成「工作台」,所以这篇文章先进行「Core Data Stack」的初始化。

1、初始化Core Data Stack

上面我们将Core Data Stack比喻成一个「工作台」,是一切操作的所在地。

不过由于iOS10新引进了NSPersistentContainer类,然后新建项目又可以选择勾选Core Data与否。所以情况变得稍稍有点复杂。

这里分三种情况:1、在既有项目(只需支持iOS10)初始化Core Data Stack;2、在既有项目(需兼容iOS8、9、10等系统)初始化Core Data Stack;3、新建项目时直接勾选了Core Data。

情况1:在既有项目添加Core Data功能(只需支持iOS10)

由于iOS10引进了NSPersistentContainer,如果单单只支持iOS10系统,初始化Core Data Stack相比以前简单很多。

代码语言:javascript
复制
// 我们先声明了一个NSPersistentContainer类型的属性:persistentContainer,在适合的时间调用initWithName:对其初始化
// 这里的Name参数,需要和后续创建的.xcdatamodeld模型文件名称一致。
_persistentContainer = [[NSPersistentContainer alloc] initWithName:@"MoveBand"];
    
// 调用loadPersistentStoresWithCompletionHandler:方法,完成Core Data Stack的最中初始化。
// 如果不能初始化成功,在Block回调中打印错误,方便调试
[_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription * _Nonnull description, NSError * _Nullable error) {
        
    if (error != nil) {
        NSLog(@"Fail to load Core Data Stack : %@", error);
        abort();
    }
    else {
        ...
    }
}];

就两步:

  • 初始化NSPersistentContainer对象;
  • 调用NSPersistentContainer的loadPersistentStoresWithCompletionHandler:完成初始化。

更详细的说明,可参考官方文档Initializing the Core Data Stack

备注:你可以仿照Xcode所创建的模版,直接在AppDelegate类中桥敲以上代码。也可以新建一个专门负责储存功能的类,在这个类中敲这段代码。(我一般不喜欢将这部分代码放在AppDelegate类中,所以我创建工程的时候,都不会勾选Use Core Data)。

情况2:在既有项目初始化Core Data Stack(需兼容iOS8、9、10等系统)

因为NSPersistentContainer不兼容iOS10之前的系统。所以,如果你已经用了NSPersistentContainer初始化了Core Data Stack,但同时也要兼容iOS8、9等系统,就需要在代码中检查,如果是旧的系统,就需要用旧的方法初始化Core Data Stack了。示例如下:

代码语言:javascript
复制
- (instancetype)init
{
    self = [super init];
    if (self) {
        NSInteger majorVersion = [NSProcessInfo processInfo].operatingSystemVersion.majorVersion;
        
        if (majorVersion < 10) {
            // iOS10以下的系统, 用旧有的方法初始化Core Data Stack
            [self initializeCoreDataLessThaniOS10];
        }
        else {
            // iOS10的系统, 用新的方法(详见上面介绍的情况1)
            [self initializeCoreData];
        }
    }
    return self;
}


- (void)initializeCoreDataLessThaniOS10 {
    // Get managed object model(拿到模型文件,也就是.xcdatamodeld文件(我们会在初始化完Core data Stack后创建))
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"MoveBand" withExtension:@"momd"];
    NSManagedObjectModel *mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
    NSAssert(mom != nil, @"Error initalizing Managed Object Model");
    
    // Create persistent store coordinator(创建NSPersistentStoreCoordinator对象(需要传入上述创建的NSManagedObjectModel对象))
    NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom];
    
    // Creat managed object context(创建NSManagedObjectContext对象(_context是声明在.h文件的属性——因为其他类也要用到这个属性))
    _context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    
    // assgin persistent store coordinator(赋值persistentStoreCoordinator)
    _context.persistentStoreCoordinator = psc;
    
    // Create .sqlite file(在沙盒中创建.sqlite文件)
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSURL *documentsURL = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
    NSURL *storeURL = [documentsURL URLByAppendingPathComponent:@"DataModel.sqlite"];
    
    // Create persistent store(异步创建NSPersistentStore并add到NSPersistentStoreCoordinator对象中,作用是设置保存的数据类型(NSSQLiteStoreType)、保存路径、是否支持版本迁移等)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        
        // 用于支持版本迁移的参数
        NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                                 [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                                 [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
        NSError *error = nil;
        NSPersistentStoreCoordinator *psc = _context.persistentStoreCoordinator;
        
        // 备注,如果options参数传nil,表示不支持版本迁移
        NSPersistentStore *store = [psc addPersistentStoreWithType:NSSQLiteStoreType
                                                     configuration:nil
                                                               URL:storeURL
                                                           options:options
                                                             error:&error];
        NSAssert(store != nil, @"Error initializing PSC: %@\n%@", [error localizedDescription], [error userInfo]);
    });
}

可以看到,旧方法初始化Core Data Stack还是比较麻烦的。

当然,如果你不想做这个判断,只用上面方法初始化即可,这个方法在新旧系统都正常工作。

情况3:直接勾选Core Data

创建项目时,如果直接勾选Core Data复选框,项目模版会在AppDelegate类中直接帮你初始化好Core Data Stack,自动创建和上面情况1类似的代码(Xcode8)

在AppDelegate.h文件

代码语言:javascript
复制
#import <UIKit/UIKit.h>
// 导入了CoreData框架
#import <CoreData/CoreData.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

// 在.h文件声明一个NSPersistentContainer类型的属性(为了让其他类可以调用)
@property (readonly, strong) NSPersistentContainer *persistentContainer;

// 声明了一个保存数据的方法
- (void)saveContext;

@end

在AppDelegate.m文件

代码语言:javascript
复制
@implementation AppDelegate

……

#pragma mark - Core Data stack

@synthesize persistentContainer = _persistentContainer;

- (NSPersistentContainer *)persistentContainer {
    @synchronized (self) {
        if (_persistentContainer == nil) {
            // 实例化NSPersistentContainer对象。
            // 注意:参数传入的名称,就是.xcdatamodeld文件名称(两者需要一直)(勾选Core Data后,会自动创建一个.xcdatamodeld文件)
            _persistentContainer = [[NSPersistentContainer alloc] initWithName:@"CoreDataTestUseCoreData"];
            
            // 加载persistent stores,实现最终的Core Data stack的创建
            [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
                // 如果有错误,打印出来
                if (error != nil) {
                    NSLog(@"Unresolved error %@, %@", error, error.userInfo);
                    abort();
                }
            }];
        }
    }
    
    return _persistentContainer;
}

#pragma mark - Core Data Saving support

- (void)saveContext {
    // 注意这句,NSManagedObjectContext对象,是通过上面创建的NSPersistentContainer对象的属性viewContext获取的,无需自己初始化(iOS10之前要自己初始化)
    NSManagedObjectContext *context = self.persistentContainer.viewContext;
    
    NSError *error = nil;
    // 保存数据,直接用的是NSManagedObjectContext的save:方法,很简单。
    if ([context hasChanges] && ![context save:&error]) {
        NSLog(@"Unresolved error %@, %@", error, error.userInfo);
        abort();
    }
}

系统帮我们创建了一个NSPersistentContainer实例,以及一个saveContext方法。(并且已经帮我们创建了.xcdatamodeld模型文件)

注意看saveContext,我们通过NSPersistentContainer的属性viewContext拿到NSManagedObjectContext对象,再通过save:方法进行数据的保存。

因为系统并没有帮我们适配旧系统,所以如果App要在非iOS10的旧系统运行,还需要做类似情况2的工作。

如果是Xcode8之前的版本自动创建的Core Data Stack,会不一样(跟情况2类似),这里不再赘述。

2、创建「managed object model」

好了,有了「工作台」,接着就需要「材料」了。也就是你要保存什么东西,这些东西有什么特性,这些东西之间有什么关系……Xcode提供了一套可视化的方案让我们「描述」这部分内容。

创建xcdatamodeld文件

快捷键:Command + N,选择Core Data栏目下的「Data Model」,就可以创建一个.xcdatamodeld模型文件(managed object model),名字随意。接着我们就可以往里面添加材料了。

添加实体、实体的特性、关系

这部分用一张图概括:

添加实体、实体的特性、关系示意图

:这里有个坑,在Xcode8中,Codegen下拉选择框中增加了Class/Definition这一选项,而且是默认的预设值,这时候系统会自动帮我们这个实体创建了NSManagedObject子类,最坑的是,这些自动创建的类,在导航面板是看不见的!!!然后你很容易再重复手动创建NSManagedObject子类,这时候就会报类似「duplicate symbol _OBJC_METACLASS_Photography in:...」这类错误。

所以,如果你想自己手动创建NSManagedObject子类,就要把系统预设的Class/Definition改为Manual/None

创建NSManagedObject子类

好了,通过上面的一步,我们知道我们要保存的是什么东西,以及知道他们是什么关系了(数据模型建好了)。

为什么要用NSManagedObject子类

这时候其实可以进行数据的增删查改了。但是这时候赋值(或者修改)一条数据,都是通过NSManagedObject类实例进行的(我们创建的实体,都是NSManagedObject类型的),类似如下:

代码语言:javascript
复制
NSManagedObject *newUser = …… // 这里聚焦在数据的赋值与取值, 暂时省略插入一条数据的方法

// 赋值
[newUser setValue:@"Antony" forKey:@"name"];
[newUser setValue:@123 forKey:@"userID"];

// 取值
NSManagedObject *selectedUser = ……
NSString *name = [selectedUser valueForKey@"name"];
……

以上的存取值方式,有点类似字典。不直观,敲字符串也容易出错。所以,我们通常都会创建NSManagedObject的子类,用点语法直接进行存取操作。

在.h文件

代码语言:javascript
复制
#import <CoreData/CoreData.h>

@interface SPKUser : NSManagedObject

@property (copy, nonatomic) NSString *name;

@property (nonatomic) int64_t userID;

@end

在.m文件

代码语言:javascript
复制
#import "SPKUser.h"

@implementation SPKUser

// 在OC中,将某个属性实现为@dynamic,表示编译器在编译时不会对这个属性的存取方法(getter/setter)做检查(由程序员自己提供存取方法)。在Core Data中,由Core Data实现。
@dynamic name;
@dynamic userID;

@end

然后就可以这样:

代码语言:javascript
复制
- (void)addNewUser {
    SPKUser *newUser = ……;
    
    newUser.name = @"Antony";
    newUser.userID = 123;
    NSLog(@"添加了一个user");
}

所以,这就是应用NSManagedObject子类的好处。

如何创建NSManagedObject子类

创建NSManagedObject子类,有如下两种办法

  • 方法1:直接Command + N创建一个新类,继承NSManagedObject类,然后定义的属性和模型文件中的一致。
  • 方法2:选中对应的实体,然后Editor > Create NSManagedObject Subclass...,系统自动生成NSManagedObject子类。 这种方法,如果有「对多」的关系,会生成2个Category(Core Data生成的NSManagedObject子类,都是以Category形式存在的)
  • CoreDataProperties:生成实体中Attributes对应的属性。Relationships也会生成对应的属性:「对多」关系是NSSet/NSOrderSet类型属性(本质是个集合),「对一」关系则是非集合的对象类型属性。
  • CoreDataGeneratedAccessors——其实就是一系列增加、删除NSOrderSet/NSSet里元素的方法。(如果没有对多关系,不会有这个Category)

注意,第二种方式创建NSManagedObject子类,默认语言是Swift,如果需要改为OC,则到「File inspector」中修改,如下:

修改创建NSManagedObject子类的语言

3、增

好啦,有了「工作台」(Core Data Stack),又有了「材料」(managed object model),可以撸起袖子干了……(第一张示意图,其实都有对增删查、保存方法有所提及)

代码语言:javascript
复制
- (void)addNewUser {
    SPKUser *newUser = [NSEntityDescription insertNewObjectForEntityForName:@"User" inManagedObjectContext:_context];
    
    newUser.name = @"Antony";
    newUser.userID = 123;
}

看以上代码,增加一条数据,并不是调用NSManagedObjectContext类中的某个方法,而是用了NSEntityDescription的类方法insertNewObjectForEntityForName:inManagedObjectContext:,第一个参数传入实体名称,第二个参数传入context(因为Core Data是支持多个context的,所以这里传入context参数以界定是在哪个context中操作)。

该方法会返回一个NSManagedObject,或其子类的对象,然后就可以对该对象进行赋值操作了。

注意:此时数据只存在内存中,并没有固化、保存到沙盒。还需要通过特定的保存方法才能固化到沙盒。

另外,不能用alloc、init方法创建一个新的对象,会崩溃。

4、删

删除数据比较简单,直接调用NSManagedObjectContextdeleteObject:方法即可。当然,要怎么获取所要删除的对象,就自己斟酌了,可以通过NSFetchRequest查询获取要删除的对象,也可以用NSFetchedResultsController的objectAtIndexPath:方法拿到要删除的对象(NSFetchedResultsController另一篇文章再介绍)

代码语言:javascript
复制
- (void)removeUser:(SPKUser *)user {
    [_context deleteObject:user];
}

5、查(Fetching Objects)

查询功能,是被官方特别强调的一个功能,据闻可以玩出很多花样儿~

代码语言:javascript
复制
- (NSArray *)allUsers {
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];
    
    NSError *error = nil;
    
    NSArray *results = [_context executeFetchRequest:request error:&error];

    if (!results) {
        NSLog(@"Error fetching Employee objects: %@\n%@", [error localizedDescription], [error userInfo]);
        abort();
    }
    
    return results;
}

上面是一个最简单的查询,调用NSManagedObjectContextexecuteFetchRequest:error:方法,传入一个NSFetchRequest对象作为参数,这个参数定义了要取回的是哪个实体。

另外,还可以通过NSPredicate(「谓语」,也有翻译为「断言」的)进行数据筛选,只获取某些符合条件的数据。还可以通过NSSortDescriptor设置获取数据的排列顺序。如下:

代码语言:javascript
复制
- (NSArray *)allUsers {
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Employee"];
    
    // 只取回firstName是Antony的数据
    NSString *firstName = @"Antony";
    [request setPredicate:[NSPredicate predicateWithFormat:@"firstName == %@", firstName]];
    
    // 取回的数据按userID进行由小到大(升序)的排序
    NSSortDescriptor *userIDSort = [NSSortDescriptor sortDescriptorWithKey:@"userID" ascending:YES];
    
    // 注意,这个参数是一个数组,所以排序可以有多个条件,比如先按身高从低到高排,满足此条件后再按照名字首字母A~Z从前到后排。这时候,身高的Sort Descriptor放在数组前面,名字的Sort Descriptor放在数组后面。
    [request setSortDescriptors:@[userIDSort]];
    
    NSError *error = nil;
    
    NSArray *results = [_context executeFetchRequest:request error:&error];

    if (!results) {
        NSLog(@"Error fetching Employee objects: %@\n%@", [error localizedDescription], [error userInfo]);
        abort();
    }
    
    return results;
}

关于NSPredicate更详细的用法,可参考官方文档:Predicate Programming Guide

6、改

修改数据,和上面的增加一条数据的情况比较相似,直接对属性进行修改。先查询到你要的数据对象,再重新赋值即可。

如果要大批量修改数据,将数据从沙盒加载到内存,再进行修改,不利于性能,所以可以使用NSBatchUpdateRequestNSBatchDeleteRequest,进行批量的修改或者删除。这种方法直接在数据库内完成,无需加载到内存,利于性能提升。(但进行批处理后,因为操作是在数据库中完成的,要注意合并更新到Context中,以保持两者一致)

关于批处理,可以参考《New in Core Data and iOS 8: Batch Updating》,这里不再展开( 其实我自己暂时也没用过:D )

7、保存

保存比较简单,直接调用NSManagedObjectContext的save:方法即可,如下:

代码语言:javascript
复制
- (void)save {
    NSError *error = nil;
    if ([_context save:&error] == NO) {
        NSAssert(NO, @"Error saving context %@\n%@", [error localizedDescription], [error userInfo]);
    }
}

也可以调用NSManagedObjectContexthasChanges方法,来判断:在数据有变化的情况下再调用save:方法。

注意:在调用save方法之前,上面做的所有操作(增、删、改),都只是保存在内存中,并不会固化到沙盒中。

版本「迁移」

应用场景:修改了数据结构(比如说某个实体增加了一个特性),这时候就要进行版本迁移了,否则已经安装旧App的手机,在更新应用后,两边数据结构不一致导致不能识别,会崩溃。

步骤:

  • 选中.xcdatamodeld文件,Editor > Add Model Version,创建一个新版的.xcdatamodeld文件
  • 切换到新版的.xcdatamodeld文件(切换成功后会有绿色的勾),如下图:

切换到新版的.xcdatamodeld文件

  • 对.xcdatamodeld文件进行你想要的修改
  • 创建NSPersistentStore的时候,options参数传一个dictionary,值如下:
代码语言:javascript
复制
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
    [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
    [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];

更详细的代码,上面用旧方法创建Core Data Stack时也有涉及。

大家也可以自己验证一下,不进行版本迁移,直接修改.xcdatamodeld文件,然后运行程序,会报什么错。

以上是自动、轻量化的版本迁移,至于更复杂的版本迁移,我目前也没有接触到,不再展开。可以参考:

自定义 Core Data 迁移

Core Data Model Versioning and Data Migration Programming Guide

End

认识CoreData-初识CoreData》系列文章,写得很详细,推荐阅读。

以上就是Core Data的入门用法(文科狗,不容易啊 XD )。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017.04.15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 「太长不看版」
  • 术语
    • Core Data Stack
      • Persistent Container
        • Managed Object Context。
          • Managed Object Model
            • Managed Object。
              • Persistent Store Coordinator
                • Persistent Store
                  • 其他
                  • 使用步骤
                    • 1、初始化Core Data Stack
                      • 情况1:在既有项目添加Core Data功能(只需支持iOS10)
                      • 情况2:在既有项目初始化Core Data Stack(需兼容iOS8、9、10等系统)
                      • 情况3:直接勾选Core Data
                    • 2、创建「managed object model」
                      • 创建xcdatamodeld文件
                      • 添加实体、实体的特性、关系
                      • 创建NSManagedObject子类
                    • 3、增
                      • 4、删
                        • 5、查(Fetching Objects)
                          • 6、改
                            • 7、保存
                            • 版本「迁移」
                            • End
                            相关产品与服务
                            数据库
                            云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
                            领券
                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档