CoreData模板代码分析

2024-05-26 10:48
文章标签 分析 代码 模板 coredata

本文主要是介绍CoreData模板代码分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

之前写过一篇CoreData的简单使用的文章,其Demo使用了Xcode中的CoreData模板(新建一个Empty模板的工程时,如果选择了Use Core Data选项,那么新建出来的工程便会附带上Core Data的代码)

但是之前并没有留意CoreData自动引入的模板代码的作用,最近又接触到了CoreData的内容,所以回头看了一下这部分代码。

首先看看Core Data的框架结构(下图来自Core Data Overview):



以下是我的对CoreData的初级认识:

1.在CoreData中有一个托管对象上下文(ManagedObjectContext),可以把它看做一个缓冲区,负责记录托管对象的状态和给出用户查询的对象等。

2.在上下文中存储的是各个托管对象(ManagedObject),也就是我们要持久化的对象数据,它们由托管对象模型(ManagedObjectModel)描述,其模型可以通过xcdatamodeld文件定制,xcdatamodeld文件在程序启动后加载到Bundle中并被解释成momd文件夹中的内容。

3.有多种方式来持久化对象数据,如SQLite数据库、XML文件、二进制文件等,这需要和底层的SQLite及File System打交道,因此要用到大量的SQL语句,使程序开发难度加大。幸好CoreData为我们给出了解决方案:持久化仓库统筹者(PersistentStoreCoordinator),CoreData将与底层的数据库和文件系统抽象成一个持久化仓库(PersistentStore),可以使用持久化仓库统筹者对各个仓库进行管理和操作,开发者并不需要关注数据的存储方式和操作查询等具体过程,此时持久化仓库统筹者就像一个ORM的角色,所以不要把CoreData简单地理解成一个ORM的框架。



要使用CoreData的相关类,首先要在项目中添加CoreData.framework并导入相关的头文件,在Use Core Data的项目中已经在pch预编译头文件中导入:

#import <Availability.h>#ifndef __IPHONE_3_0
#warning "This project uses features only available in iOS SDK 3.0 and later."
#endif#ifdef __OBJC__#import <UIKit/UIKit.h>#import <Foundation/Foundation.h>#import <CoreData/CoreData.h>
#endif


下面是AppDelegate.h中自动生成的代码:

// managedObjectContext,managedObjectModel,persistentStoreCoordinator全部是一次性初始化的// 托管对象上下文,其中包含多个托管对象
@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;// 托管对象模型:用来描述托管对象
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;// 持久化仓库统筹者:用来协调托管对象的存储过程和具体存储方式
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;// 将托管对象上下文写入到持久化仓库中
- (void)saveContext;// 获取程序Documents目录
- (NSURL *)applicationDocumentsDirectory;

AppDelegate.m文件内容见下文。

首先是AppDelegate中的几个方法,只有applicationWillTerminate方法中有和CoreData相关的代码:

- (void)applicationWillTerminate:(UIApplication *)application {// Saves changes in the application's managed object context before the application terminates.[self saveContext];
}
在程序将要终止时,要调用self的saveContext方法保存托管对象上下文。


saveContext方法实现如下:

- (void)saveContext {NSError *error = nil;NSManagedObjectContext *managedObjectContext = self.managedObjectContext;if (managedObjectContext != nil) {// 在上下文发送了变化的情况下才保存上下文,如果保存出错就报错并终止程序运行if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {// Replace this implementation with code to handle the error appropriately.// 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. NSLog(@"Unresolved error %@, %@", error, [error userInfo]);abort();}}
}
注意

managedObjectContext hasChanges] && ![managedObjectContext save:&error]
这一行表明,只有上下文发生了变化才执行后面的save方法。如果save方法返回NO,那么保存失败,应该实现出错处理的代码。


然后是托管对象上下文的getter方法:

- (NSManagedObjectContext *)managedObjectContext {// lazy initialization的getter方法// 此时在类中访问属性时,应该使用getter方法来获取(self.xx),不要直接使用实例变量(_xx)if (_managedObjectContext != nil) {return _managedObjectContext;}NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];if (coordinator != nil) {// 初始化托管对象上下文,并将其与持久化仓库统筹者相关联_managedObjectContext = [[NSManagedObjectContext alloc] init];[_managedObjectContext setPersistentStoreCoordinator:coordinator];}return _managedObjectContext;
}

这里getter方法使用了lazy initialization的方式初始化,也就是一次性的初始化,因此在AppDelegate.m中,不能通过实例变量(即_managedObjectContext)的方式来获取,只能通过getter方法(self.managedObjectContext或[self managedObjectContext])来获取,否则该属性可能没有被初始化。

在新建一个托管对象上下文对象后,还要将其和一个持久化仓库统筹者相关联,实际上统筹者已经和各个持久化仓库相关联,这里就搭起了上下文到各个仓库之间的桥梁。


然后是持久化仓库统筹者的getter方法:

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {// lazy initialization的getter方法if (_persistentStoreCoordinator != nil) {return _persistentStoreCoordinator;}// App的当前路径 / Documents / AppName.sqliteNSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreDataRef.sqlite"];NSError *error = nil;// 通过托管对象模型来初始化持久化仓库统筹者_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];// 根据配置选项将storeURL指定的存储介质(sqlite,XML,二进制文件,内存等)添加到统筹者的管辖范围内if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreTypeconfiguration:nilURL:storeURLoptions:nilerror:&error]){/*Replace this implementation with code to handle the error appropriately.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. Typical reasons for an error here include:* The persistent store is not accessible;* The schema for the persistent store is incompatible(冲突) with current managed object model.Check the error message to determine what the actual problem was.If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.If you encounter schema incompatibility errors during development, you can reduce their frequency by:* Simply deleting the existing store:[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]* Performing automatic lightweight migration by passing the following dictionary as the options parameter:@{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES}Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.*/NSLog(@"Unresolved error %@, %@", error, [error userInfo]);abort();}    return _persistentStoreCoordinator;
}

这里同样是 lazy initialization的初始化方式。

使用托管对象模型创建统筹者对象后,将持久化仓库添加到自己的管辖范围之下,添加的仓库必须指定数据的保存方式,如存储路径,存储的类型(SQLite数据库,XML文件,二进制文件,内存等)。另外下列方法给出Documents目录的路径:

- (NSURL *)applicationDocumentsDirectory {return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}


托管对象模型的getter方法:

- (NSManagedObjectModel *)managedObjectModel {// lazy initialization的getter方法if (_managedObjectModel != nil) {return _managedObjectModel;}// momd文件由xcdatamodeld生成,用来初始化对象模型对象NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"CoreDataRef" withExtension:@"momd"];_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];return _managedObjectModel;
}

同样是 lazy initialization的初始化方式。

数据模型根据Bundle中的momd目录下的文件创建:


Bundle中的momd目录由项目中的xcdatamodeld文件加载后生成,xcdatamodeld文件的内容就是一个对象图,可以让我们更清晰直观地设计对象模型。


至此,所有由CoreData自动引入的代码分析完毕。

事实上,如果不想使用CoreData模板来导入该框架,那么肯定要理解上述代码的作用,才能灵活地在项目中加入CoreData框架。




这篇关于CoreData模板代码分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1004249

相关文章

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

poj3468(线段树成段更新模板题)

题意:包括两个操作:1、将[a.b]上的数字加上v;2、查询区间[a,b]上的和 下面的介绍是下解题思路: 首先介绍  lazy-tag思想:用一个变量记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。 比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

活用c4d官方开发文档查询代码

当你问AI助手比如豆包,如何用python禁止掉xpresso标签时候,它会提示到 这时候要用到两个东西。https://developers.maxon.net/论坛搜索和开发文档 比如这里我就在官方找到正确的id描述 然后我就把参数标签换过来

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

uva 1342 欧拉定理(计算几何模板)

题意: 给几个点,把这几个点用直线连起来,求这些直线把平面分成了几个。 解析: 欧拉定理: 顶点数 + 面数 - 边数= 2。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#inc

uva 11178 计算集合模板题

题意: 求三角形行三个角三等分点射线交出的内三角形坐标。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <

poj 2104 and hdu 2665 划分树模板入门题

题意: 给一个数组n(1e5)个数,给一个范围(fr, to, k),求这个范围中第k大的数。 解析: 划分树入门。 bing神的模板。 坑爹的地方是把-l 看成了-1........ 一直re。 代码: poj 2104: #include <iostream>#include <cstdio>#include <cstdlib>#include <al

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者