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

相关文章

Go标准库常见错误分析和解决办法

《Go标准库常见错误分析和解决办法》Go语言的标准库为开发者提供了丰富且高效的工具,涵盖了从网络编程到文件操作等各个方面,然而,标准库虽好,使用不当却可能适得其反,正所谓工欲善其事,必先利其器,本文将... 目录1. 使用了错误的time.Duration2. time.After导致的内存泄漏3. jsO

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

使用C#代码在PDF文档中添加、删除和替换图片

《使用C#代码在PDF文档中添加、删除和替换图片》在当今数字化文档处理场景中,动态操作PDF文档中的图像已成为企业级应用开发的核心需求之一,本文将介绍如何在.NET平台使用C#代码在PDF文档中添加、... 目录引言用C#添加图片到PDF文档用C#删除PDF文档中的图片用C#替换PDF文档中的图片引言在当

C#使用SQLite进行大数据量高效处理的代码示例

《C#使用SQLite进行大数据量高效处理的代码示例》在软件开发中,高效处理大数据量是一个常见且具有挑战性的任务,SQLite因其零配置、嵌入式、跨平台的特性,成为许多开发者的首选数据库,本文将深入探... 目录前言准备工作数据实体核心技术批量插入:从乌龟到猎豹的蜕变分页查询:加载百万数据异步处理:拒绝界面

用js控制视频播放进度基本示例代码

《用js控制视频播放进度基本示例代码》写前端的时候,很多的时候是需要支持要网页视频播放的功能,下面这篇文章主要给大家介绍了关于用js控制视频播放进度的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言html部分:JavaScript部分:注意:总结前言在javascript中控制视频播放

Spring Boot 3.4.3 基于 Spring WebFlux 实现 SSE 功能(代码示例)

《SpringBoot3.4.3基于SpringWebFlux实现SSE功能(代码示例)》SpringBoot3.4.3结合SpringWebFlux实现SSE功能,为实时数据推送提供... 目录1. SSE 简介1.1 什么是 SSE?1.2 SSE 的优点1.3 适用场景2. Spring WebFlu

java之Objects.nonNull用法代码解读

《java之Objects.nonNull用法代码解读》:本文主要介绍java之Objects.nonNull用法代码,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录Java之Objects.nonwww.chinasem.cnNull用法代码Objects.nonN

Spring事务中@Transactional注解不生效的原因分析与解决

《Spring事务中@Transactional注解不生效的原因分析与解决》在Spring框架中,@Transactional注解是管理数据库事务的核心方式,本文将深入分析事务自调用的底层原理,解释为... 目录1. 引言2. 事务自调用问题重现2.1 示例代码2.2 问题现象3. 为什么事务自调用会失效3

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

python+opencv处理颜色之将目标颜色转换实例代码

《python+opencv处理颜色之将目标颜色转换实例代码》OpenCV是一个的跨平台计算机视觉库,可以运行在Linux、Windows和MacOS操作系统上,:本文主要介绍python+ope... 目录下面是代码+ 效果 + 解释转HSV: 关于颜色总是要转HSV的掩膜再标注总结 目标:将红色的部分滤