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;最后将持久化存储协调器赋值给托管对象上下文
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· NetPad:一个.NET开源、跨平台的C#编辑器
· PowerShell开发游戏 · 打蜜蜂
· 凌晨三点救火实录:Java内存泄漏的七个神坑,你至少踩过三个!
2017-10-31 Xcode -(Swift版)Storyboard教程 1.5:使用原型单元格的子类
2017-10-31 UI基础 - storyboard_swift版 02:Prototype Cell