iOS基础 - CoreData

▶ 什么是 CoreData

CoreData 是苹果公司封装的进行数据持久化的框架,是 iOS 5 之后新出来的的一个框架, 它允许按照实体-属性-值模型组织数据,并以 XML、二进制文件或者 SQLite 数据文件的格式持久化数据。CoreData 可以节省代码量:一般可达 30% 到 70%;它支持可视化建模;支持模型版本升级

CoreData 的底层是用 Sqlite3 来实现的,我们在内存中的对象时如何最后写入 Sqlite3 数据库中去的 ?其实是通过一个叫 Coordinator 的东西,它究竟是怎么实现的,就不要去关心了。CoreData 主要提供 对象-关系映射 功能(ORM:Object Relational Mapping),把 OC对象 转化为数据保存到文件,也可以数据转化为 OC对象

CoreData数据库 和 Sqlite数据库 两者的区别

A. Sqlite数据库:它基于 C 接口,需要使用 sql语句,但是代码较为繁琐;在处理大量数据时,表关系更为直观;在 OC 中不是可视化的;可以跨平台使用:iOS 和安卓

B. CoreData 数据库:可视化,有 undo/redo 能力;可以实现多种文件格式 NSSQLiteStoreType、NSBinaryStoreType、NSInMemoryStoreType、NSXMLStoreType;不能跨平台使用,只支持 iOS;苹果官方 API 支持,与 iOS 结合更紧密

▶ CoreData 的核心类

NSManagedObjectConext:被管理对象上下文(数据管理器)。相当于一个临时数据库,它负责应用与数据库之间的交互,增删改查基本操作都要用到,在实际开发中我们只关注该层

NSManagedObjectModel:被管理对象模型(数据模型器)。它可以添加实体及实体的属性,为 ***.xcdatamodeld文件,是 CoreData数据库 的可视化文件

NSPersistentStoreCoordinator:持久化存储助理(数据链接器)。是整个 CoreData 的核心,用来配置数据存储的名字、位置、存储方式等

NSManagedObject:是从 CoreData 中取出来的对象,默认都是 NSManagedObject 对象,通过键值对来存取所有的实体属性,相当于数据库中的表格记录

NSFetchRequest:获取数据时的请求

▶ CoreData 的使用方式

DemoA:iOS 10 之前的版本

A. 新建项目并勾选 CoreData:它会将 CoreData.framework 增加到我们工程的 Frameworks 列表中,并在 AppDelegate 中增加了一些关于 CoreData 的代码

B. 选中 ***.xcdatamodel 文件(Xcode 勾选 Use Core Data 时系统自动生成的文件,相当于数据库),创建 MyClass 和 Student两个实体(实体就相当于数据库中的表)并为其添加属性

C. 根据实体创建托管对象

选中 MyClass、Student 

之后系统会自动帮你生成 MyClass 和 Student 两个类文件且属性、映射关系等均已实现。下面以  MyClass 为例

D. 代码实现:有这样一个需求,我们在程序启动时利用 CoreData 插入数据并打印所所插入的数据信息!界面搭建则使用 storyBoard 拖一个 tableView 对数据进行展示,并完成增、删、改、查功能

// - AppDelegate.h 

 1 #import <UIKit/UIKit.h>
 2 #import <CoreData/CoreData.h>
 3 
 4 @interface AppDelegate : UIResponder <UIApplicationDelegate>
 5 @property (strong, nonatomic) UIWindow *window;
 6 
 7 // -------------- 以下代码全是系统自动生成 ----------------
 8 
 9 // 管理数据库上下文的对象,可以进行增、删、改、查
10 @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
11 // 数据模型
12 @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
13 // 数据库持久化协调器,实际的工作都是由它来处理
14 @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
15 // 存储
16 - (void)saveContext;
17 
18 // 文件路径
19 - (NSURL *)applicationDocumentsDirectory;
20 
21 @end

// - AppDelegate.m 

  1 #import "AppDelegate.h"
  2 #import "Student.h"
  3 @interface AppDelegate ()
  4 
  5 @end
  6 
  7 @implementation AppDelegate
  8 
  9 //  我们在 didFinishLaunchingWithOptions 中实现插入、查询功能
 10 //  然后在 TableViewController 实现删改操作
 11 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
 12     NSLog(@"%@",NSHomeDirectory());
 13     
 14     //-----------------------  CoreData 的使用 -----------------------
 15     
 16     // ------插入数据:添加对象------
 17     // 方式一
 18     // Student *student1 = [NSEntityDescription insertNewObjectForEntityForName:@"Student" inManagedObjectContext:self.managedObjectContext];
 19     
 20     // 方式二
 21     NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Student" inManagedObjectContext:self.managedObjectContext];
 22     Student *student1 = [[Student alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:self.managedObjectContext];
 23     
 24     // 赋值
 25     student1.name = @"Solina";
 26     student1.sex = @"female";
 27     student1.age = @16;
 28     
 29     // --------- 存储数据 ---------
 30     // 方式一
 31     BOOL result = [_managedObjectContext save:nil];
 32     if (result) {
 33         NSLog(@"添加数据成功");
 34     }else{
 35         NSLog(@"添加数据失败");
 36     }
 37     
 38     // 方式二
 39     // [self saveContext];
 40     
 41     // -------- 查询数据 --------
 42     NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Student"];
 43     
 44     // 谓词:检索条件一定要根据实体中的属性来设置
 45     NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name == %@",@"Solina"];
 46     request.predicate = predicate;
 47     // 排序
 48     NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:@"age" ascending:YES];
 49     request.sortDescriptors = @[descriptor];
 50     NSError *error = nil;
 51     NSArray *resultArray = [self.managedObjectContext executeFetchRequest:request error:&error];
 52     
 53     // 打印结果
 54     NSLog(@"%@",resultArray);
 55     
 56     return YES;
 57 }
 58 
 59 // 退出程序时保存数据
 60 - (void)applicationWillTerminate:(UIApplication *)application {
 61     [self saveContext];
 62 }
 63 
 64 
 65 // ---------------------- 以下代码全是系统自动生成 -----------------------
 66 #pragma mark - Core Data stack
 67 // 这些都是创建时系统自动生成
 68 @synthesize managedObjectContext = _managedObjectContext;
 69 @synthesize managedObjectModel   = _managedObjectModel;
 70 @synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
 71 
 72 // 返回 CoreData 存储的路径
 73 - (NSURL *)applicationDocumentsDirectory {
 74     
 75     // 打印路径
 76     NSLog(@"%@",[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]);
 77     return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
 78 }
 79 // 获取管理对象
 80 - (NSManagedObjectModel *)managedObjectModel {
 81     if (_managedObjectModel != nil) {
 82         return _managedObjectModel;
 83     }
 84     // 从应用程序中加载模型文件
 85     // momd 是编译后的文件后缀
 86     NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"CoreDataDemo" withExtension:@"momd"];
 87     _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
 88     return _managedObjectModel;
 89 }
 90 // 数据持久化协调器(真正做事情的)
 91 - (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
 92     
 93     if (_persistentStoreCoordinator != nil) {
 94         return _persistentStoreCoordinator;
 95     }
 96     
 97     // 连接器对象关联的实体模型
 98     _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
 99     //  定义数据存储的路径
100     NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreDataDemo.sqlite"];
101     NSError *error = nil;
102     NSString *failureReason = @"There was an error creating or loading the application's saved data.";
103     
104     // NSSQLiteStoreType 这个参数决定文件存储的形式(sqlite、XML、二进制等)
105     // 版本升级的话:把 options 原参数 nil 改成字典 @{NSMigratePersistentStoresAutomaticallyOption:@YES} ,意味着自动升级
106     if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:@{NSMigratePersistentStoresAutomaticallyOption:@YES} error:&error]) {
107         NSMutableDictionary *dict = [NSMutableDictionary dictionary];
108         dict[NSLocalizedDescriptionKey] = @"Failed to initialize the application's saved data";
109         dict[NSLocalizedFailureReasonErrorKey] = failureReason;
110         dict[NSUnderlyingErrorKey] = error;
111         error = [NSError errorWithDomain:@"YOUR_ERROR_DOMAIN" code:9999 userInfo:dict];
112         
113         NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
114         // abort()会导致应用程序生成一个崩溃日志和终止。
115         abort();
116     }
117     
118     return _persistentStoreCoordinator;
119 }
120 // 获取数据库上下文
121 - (NSManagedObjectContext *)managedObjectContext {
122     
123     if (_managedObjectContext != nil) {
124         return _managedObjectContext;
125     }
126     
127     // 创建数据持久化协调器
128     NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
129     if (!coordinator) {
130         return nil;
131     }
132 
133     // ConcurrencyType 并发类型,是一个枚举值
134     //      NSMainQueueConcurrencyType      主队列并发类型   2
135     //      NSPrivateQueueConcurrencyType   私有队列并发类型  1
136     //      NSConfinementConcurrencyType    限制并发类型     0
137     _managedObjectContext = [[NSManagedObjectContext alloc] init];
138     
139     // 数据连接器 关联 被管理上下文
140     [_managedObjectContext setPersistentStoreCoordinator:coordinator];
141     return _managedObjectContext;
142 }
143 
144 #pragma mark - Core Data Saving support
145 - (void)saveContext {
146     NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
147     if (managedObjectContext != nil) {
148         NSError *error = nil;
149         if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
150             NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
151             abort();
152         }
153     }
154 }
155 
156 @end

// - TableViewController.h

#import <UIKit/UIKit.h>
#import "AppDelegate.h"
@interface TableViewController : UITableViewController
// 右上方的添加按钮
- (IBAction)addModel:(id)sender;
// 数据源
@property(nonatomic,strong)NSMutableArray *dataSource;
// 引入 AppDelegate
@property(nonatomic,strong)AppDelegate *myAPPDelegate;
@end

// - TableViewController.m

 1 #import "TableViewController.h"
 2 #import "Student.h"
 3 @interface TableViewController ()
 4 
 5 @end
 6 
 7 @implementation TableViewController
 8 
 9 - (void)viewDidLoad {
10     [super viewDidLoad];
11     
12     self.dataSource = [NSMutableArray arrayWithCapacity:1];
13     self.myAPPDelegate = (id)[UIApplication sharedApplication].delegate;
14     
15     // 我们已经在 APP启动 时新增了些数据
16     // 下面我们开始查询数据
17     NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Student"];
18     NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"age" ascending:YES];
19     request.sortDescriptors = @[sortDescriptor];
20     NSError *error = nil;
21     NSArray *result = [self.myAPPDelegate.managedObjectContext executeFetchRequest:request error:&error];
22     
23     // 获取数据
24     [self.dataSource addObjectsFromArray:result];
25 }
26 
27 #pragma mark - Table view data source
28 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
29     
30     return 1;
31 }
32 
33 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
34     
35     return self.dataSource.count;
36 }
37 
38 
39 // ---------- CoreData修改操作 -----------
40 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
41     
42     Student *stu = (Student*)self.dataSource[indexPath.row];
43     stu.name = @"Rose";
44     [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
45     // 数据持久化
46     [self.myAPPDelegate saveContext];
47     
48 }
49 
50 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
51     
52     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CellID" forIndexPath:indexPath];
53     Student *stuA = self.dataSource[indexPath.row];
54     cell.textLabel.text = [NSString stringWithFormat:@"%@ ----- %@", stuA.name,stuA.age];
55     return cell;
56 }
57 
58 - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
59     return YES;
60 }
61 
62 
63 //  ------ CoreData删除操作 --------
64 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
65     
66     if (editingStyle == UITableViewCellEditingStyleDelete) {
67         
68         // 删除数据
69         Student *stu = self.dataSource[indexPath.row];
70         [self.dataSource removeObject:stu];
71         // 注意数据管理器中的数据也要同步删除
72         [self.myAPPDelegate.managedObjectContext deleteObject:stu];
73         // 永久保存也需要同步更新
74         [self.myAPPDelegate saveContext];
75         
76         // 更新 UI
77         [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
78     }
79 }
80 
81 
82 // ------ CoreData新增操作 --------
83 - (IBAction)addModel:(id)sender {
84     
85     NSEntityDescription *description = [NSEntityDescription entityForName:@"Student" inManagedObjectContext:self.myAPPDelegate.managedObjectContext];
86     Student *stu = [[Student alloc] initWithEntity:description insertIntoManagedObjectContext:self.myAPPDelegate.managedObjectContext];
87     stu.name = @"Puma";
88     int age = arc4random()%10+10;
89     stu.age = [NSNumber numberWithInt:age];
90     [self.dataSource addObject:stu];
91     
92     // 更新UI
93     [self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:self.dataSource.count-1 inSection:0]] withRowAnimation:UITableViewRowAnimationLeft];
94     // 更新数据
95     [self.myAPPDelegate saveContext];
96 }
97 
98 @end

运行效果

DemoB:iOS10 之后的版本

A. 在撸代码之前,先了解下新增的 NSPersistentContainer!找到源码,我们发现它是将之前方法进行了封装

 1 #import <Foundation/NSArray.h>
 2 #import <Foundation/NSDictionary.h>
 3 #import <Foundation/NSError.h>
 4 #import <CoreData/NSManagedObjectContext.h>
 5 #import <CoreData/NSPersistentStoreCoordinator.h>
 6 #import <CoreData/NSManagedObjectModel.h>
 7 #import <CoreData/NSPersistentStoreDescription.h>
 8 
 9 @class NSURL;
10 
11 
12 // 版本要求
13 API_AVAILABLE(macosx(10.12),ios(10.0),tvos(10.0),watchos(3.0))
14 
15 // 将之前的属性直接封装
16 @interface NSPersistentContainer : NSObject {
17 }
18 
19 /*
20 *  name 表示保存的数据库文件名称
21 *  默认模型文件名称为 name
22 */
23 + (instancetype)persistentContainerWithName:(NSString *)name;
24 
25 /*
26 * name  表示保存的数据库文件名称
27 * model 对象管理模型
28 */
29 + (instancetype)persistentContainerWithName:(NSString *)name managedObjectModel:(NSManagedObjectModel *)model;
30 
31 // 返回沙盒中存储数据库的文件夹 URL 路径
32 // 这个文件夹是动态创建的 Library->Application Support
33 + (NSURL *)defaultDirectoryURL;
34 
35 // 当前 NSPersistentContainer 容器的名称
36 @property (copy, readonly) NSString *name;
37 // 自动生成的管理对象上下文,这个上下文默认的操作类型是 NSMainQueueConcurrencyType 主线程
38 @property (strong, readonly) NSManagedObjectContext *viewContext;
39 @property (strong, readonly) NSManagedObjectModel *managedObjectModel;
40 @property (strong, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
41 // 存储器描述数组
42 @property (copy) NSArray<NSPersistentStoreDescription *> *persistentStoreDescriptions;
43 
44 
45 - (instancetype)initWithName:(NSString *)name;
46 - (instancetype)initWithName:(NSString *)name managedObjectModel:(NSManagedObjectModel *)model NS_DESIGNATED_INITIALIZER;
47 // 加载存储器,此方法必须要调用,否则无法存储数据
48 // block 中 NSPersistentStoreDescription 用于描述生成的存储器信息
49 // 如:数据库文件路径、存储类型等
50 - (void)loadPersistentStoresWithCompletionHandler:(void (^)(NSPersistentStoreDescription *, NSError * _Nullable))block;
51 // 返回一个基于多线程的管理对象上下文,我们无需关心多线程的内部实现以及线程安全,由 NSPersistentContainer 新创建一个
52 // 调用这个方法之后,对返回的上下文做一些数据的处理都是在子线程中完成的,可以用于处理对数据库进行大量数据操作的场景
53 - (NSManagedObjectContext *)newBackgroundContext NS_RETURNS_RETAINED;
54 // 使用存储调度器快速在多线程中操作数据库,效率非常高
55 - (void)performBackgroundTask:(void (^)(NSManagedObjectContext *))block;
56 
57 @end

这时候 AppDelegate.m文件 中的方法只有两个

// - AppDelegate.h

#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (readonly, strong) NSPersistentContainer *persistentContainer;
- (void)saveContext;
@end

// - AppDelegate.m

 1 #pragma mark - Core Data stack
 2 
 3 @synthesize persistentContainer = _persistentContainer;
 4 
 5 - (NSPersistentContainer *)persistentContainer {
 6     // The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.
 7     @synchronized (self) {
 8         if (_persistentContainer == nil) {
 9             _persistentContainer = [[NSPersistentContainer alloc] initWithName:@"DemoTest"];
10             [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
11                 if (error != nil) {
12                     // Replace this implementation with code to handle the error appropriately.
13                     // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
14                     
15                     /*
16                      Typical reasons for an error here include:
17                      * The parent directory does not exist, cannot be created, or disallows writing.
18                      * The persistent store is not accessible, due to permissions or data protection when the device is locked.
19                      * The device is out of space.
20                      * The store could not be migrated to the current model version.
21                      Check the error message to determine what the actual problem was.
22                     */
23                     NSLog(@"Unresolved error %@, %@", error, error.userInfo);
24                     abort();
25                 }
26             }];
27         }
28     }
29     
30     return _persistentContainer;
31 }
32 
33 #pragma mark - Core Data Saving support
34 
35 - (void)saveContext {
36     NSManagedObjectContext *context = self.persistentContainer.viewContext;
37     NSError *error = nil;
38     if ([context hasChanges] && ![context save:&error]) {
39         // Replace this implementation with code to handle the error appropriately.
40         // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
41         NSLog(@"Unresolved error %@, %@", error, error.userInfo);
42         abort();
43     }
44 }

B. 我们新增 Student实体,并添加添加 name、sex、age 属性

C. 接着为之创建托管对象,系统就会自动创建以下 4 个文件

// - Student+CoreDataProperties.h

#import "Student+CoreDataClass.h"
@interface Student (CoreDataProperties)
+ (NSFetchRequest<Student *> *)fetchRequest;
@property (nullable, nonatomic, copy) NSString *name;
@property (nullable, nonatomic, copy) NSString *sex;
@property (nonatomic) int64_t age;
@end

// - Student+CoreDataProperties.m

#import "Student+CoreDataProperties.h"
@implementation Student (CoreDataProperties)
+ (NSFetchRequest<Student *> *)fetchRequest {
    return [NSFetchRequest fetchRequestWithEntityName:@"Student"];
}
@dynamic name;
@dynamic sex;
@dynamic age;
@end

// - Student+CoreDataClass.h

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@interface Student : NSManagedObject
@end
#import "Student+CoreDataProperties.h"

// - Student+CoreDataClass.m 

#import "Student+CoreDataClass.h"
@implementation Student
@end

D. 代码实现

// - AppDelegate.h

#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (readonly, strong) NSPersistentContainer *persistentContainer;
- (void)saveContext;
@end

// - AppDelegate.m

 1 #import "AppDelegate.h"
 2 #import "Student+CoreDataClass.h"
 3 @interface AppDelegate ()
 4 
 5 @end
 6 
 7 @implementation AppDelegate
 8 
 9 // 需要引入头文件 Student+CoreDataClass.h
10 // 我们在 didFinishLaunchingWithOptions: 中做一些简单的数据操作:添加、存储、删除
11 // 除了引用的头文件和该方法中的代码,其他代码均是系统生成
12 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
13 
14     // 添加数据
15     Student *newEintity = [NSEntityDescription insertNewObjectForEntityForName:@"Student" inManagedObjectContext:self.persistentContainer.viewContext];
16     newEintity.name = @"张三";
17 
18     [self saveContext];
19 
20     // 删除数据
21     NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Student"];
22     NSPredicate *predic = [NSPredicate predicateWithFormat:@"name = %@",@"张三"];
23     request.predicate = predic;
24     NSArray *arr = [self.persistentContainer.viewContext executeFetchRequest:request error:nil];
25     if (arr.count > 0) {
26         [self.persistentContainer.viewContext deleteObject:arr.firstObject];
27         [self saveContext];
28     }
29 
30     return YES;
31 }
32 
33 
34 #pragma mark - UISceneSession lifecycle
35 
36 
37 - (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
38     return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
39 }
40 
41 
42 - (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions {
43 }
44 
45 
46 #pragma mark - Core Data stack
47 
48 @synthesize persistentContainer = _persistentContainer;
49 
50 - (NSPersistentContainer *)persistentContainer {
51     @synchronized (self) {
52         if (_persistentContainer == nil) {
53             _persistentContainer = [[NSPersistentContainer alloc] initWithName:@"iOSWithCoreData"];
54             [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
55                 if (error != nil) {
56                     NSLog(@"Unresolved error %@, %@", error, error.userInfo);
57                     abort();
58                 }
59             }];
60         }
61     }
62     
63     return _persistentContainer;
64 }
65 
66 #pragma mark - Core Data Saving support
67 - (void)saveContext {
68     NSManagedObjectContext *context = self.persistentContainer.viewContext;
69     NSError *error = nil;
70     if ([context hasChanges] && ![context save:&error]) {
71         NSLog(@"Unresolved error %@, %@", error, error.userInfo);
72         abort();
73     }
74 }
75 
76 @end

▶ CoreData 模型升级

CoreData 支持随着 App开发 的推进而带来的对 NSManagedObjectModel 升级或修改的管理。如果你要改变你的模型,你就必须要改变现有存储中的数据:即数据存储格式,这被称为数据迁移!具体实现步骤如下

A. 选中 ***.xcdatamodeld 文件,选择 Editor -> Add Model Version

B. 新建的 iosWithCoreData 2.xcdatamodel 如下

你可以在工程右侧属性面板的当前数据版本,这里我们选择了新版本 

C. 更新实体:为 Student实体 新增 score属性

在为 Student实体 创建新的托管对象之前,我们要在 APPDelegate.m文件 中修改 persistentStoreCoordinator方法,使其自动升级

D 最后为对应的实体创建新的托管对象即可:它会覆盖掉原来的 Student实体

注:如果你想要使 model版本 回退,则在工程右侧属性面板中选择 旧版model,然后选择对应的实体、并重复创建托管对象这一操作即可(model升级或回退,其实就是不同版本之间的覆盖)

▶ 结语

CoreData 的使用流程

A. 模型文件操作

第一步:创建模型文件,后缀名为 .xcdatamodeld。创建模型文件之后,可以在其内部进行添加实体等操作 ,用于表示数据库文件的数据结构

第二步:添加实体、属性 。实体表示数据库文件中的表结构

第三步:根据指定实体,创建托管对象类文件

B. 实例化上下文对象

第一步:创建托管对象上下文 NSManagedObjectContext

第二步:创建托管对象模型    NSManagedObjectModel

第三步:根据托管对象模型,创建持久化存储协调器 NSPersistentStoreCoordinator

第四步:关联并创建本地数据库文件,并返回持久化存储对象 NSPersistentStore;最后将持久化存储协调器赋值给托管对象上下文

 

posted on 2022-10-31 02:53  低头捡石頭  阅读(568)  评论(0编辑  收藏  举报

导航