一、CoreData是不是ORM?

在很多教程中,CoreData被认为是一套ORM框架,虽然它确实具备许多ORM的功能,但更准确地说,它其实是一套“可视化数据持久化框架”,通俗讲就是提供一个可视界面,帮助你把你的数据对象“持久化”到“磁盘”上,使得程序再次启动后它们都还在。关于CoreData是否ORM,和直接使用SQLite的关系,StackOverflow上有一个被Closed的讨论,感兴趣自己看看:[Go to StackOverflow]
二、别的教程却讲了一大堆的东西

CoreData的底层是用Sqlite3来实现的,当然你也可以换,但这样有什么好处呢?麻烦,且不知道有什么坑,即使你不换,坑也够多的了。我们需要了解的并不是它的每一个细节,而是我们要用到的部分,对于框架总体,只需要知道个大概就可以了。

我们在内存中的对象时如何最后写入Sqlite3数据库中去的?其实是通过一个叫“Coordinator”的东西,这个东西我们会在接下去的代码中会看到,它究竟是怎么实现的,就不要去关心了,反正之后我们也不会直接用到。另一个东西叫“Context”,我们所有的动作,都要执行在Context上,由这个Context去调用Coordinator。

其它呢?还有“Managed Object”,简称MO,我们要持久化的对象不能是自己随便创建的阿猫阿狗的类,必须是MO,通过CoreData查出来的对象也是MO(好吧,本文后面会讲到返回非MO的查询^_^),它们派生自NSManagedObject。

最后一个是MOM,就是“Managed Object Model”,看到Model我一开还搞糊涂,我以为是对象实体,其实它就是你创建的模型啊,在你的XCode的导航栏中看到的那个“xxx.xcdatamodeld”的玩意儿就是了,这根本没什么好说的。实在要说的话,我想说那个xxx.xcdatamodeld其实是一个目录,进去看里面有个叫xxx.xcdatamodel的文件,就是你的“建模”了,但最终生成到应用程序包(bundle)中的model以及sqlite3数据库文件的名字跟这个并不一致,后面我们能看到,这里先不表。

所以你真正要记住的东西无非就是:Context(上下文,所有动作都要执行在一个Context上)和MO。简单吧?
三、创建工程
我们来做一个小小的信息系统,用来管理大学校园中的老师、学生、班级和课程的关系。

创建一个Empty Application,叫“CollegeManagementSystem”,记得给“Use Core Data”打上勾。

“Use Core Data”这个勾给我们做了些额外的工作,一是将“CoreData.framework”增加到我们工程的Frameworks列表中来了。二是在AppDelegate中增加了一些关于CoreData的代码,前面提到的Coordinator,Context和MOM你都能看到:

@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
@property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;

在AppDelegate.m中还指定了底层所使用的那个Sqlite数据库文件的名字,记一下这个名字,之后我们要直接打开那个数据库文件看个究竟。如果你的工程没勾选“Use Core Data”这个选项,你也可以模仿一个新创建的“Use Core Data”的工程把必要的代码添加上去,完全没问题。

另外,这里有些东西要讲讲,在AppDelegate.m中:

// Returns the managed object model for the application.
// If the model doesn't already exist, it is created from the application's model.
- (NSManagedObjectModel *)managedObjectModel
{if (_managedObjectModel != nil) {return _managedObjectModel;}NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"CollegeManagementSystem" withExtension:@"momd"];_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];return _managedObjectModel;
}

这段代码提及到的的“CollegeManagementSystem.momd”即是前面提到的MOM,这是编译器生成在应用程序bundle里的MOM的名称,和前面的XXX.xcdatamodeld是有些差别的。再看看同一文件中的“persistentStoreCoordinator”方法,里面会告诉你sqlite数据库文件的名称。

四、逻辑及建模

这里我先描述下我们的业务逻辑(跟现实可能有些出入,别在意这些细节):

一共有4个实体类型,教师,课程,学生和班级。
学生必须属于某个班级,删除一个班级,就会连带删除属于它的所有学生。
学生可以选修若干门课程,同一课程也可以被若干学生选修。
一门课程有且只有一个授课教师,而一个教师可以教多门课程,
删除一个教师,就会删除所有这个教师的授课课程。
一个班级有一个班主任,由一位教师担当,一位教师最多只能担当一个班级的班主任。
每个实体类型都有一个名字,学生实体还有一个年龄。

现在打开那个“CollegeManagementSystem.xcdatamodeld”来建模了,实体,也就是Entity,每个实体有若干个属性,也就是Attribute,如名字年龄,另有Relationship来描述实体之间的关系,如图去编辑吧(由于“class”跟Objective C的关键字冲突,所以我命名为“MyClass”):

编辑的过程应该不难,按照上图提示的地方去操作。各个Entity的name属性都是String类型,学生的Age为Interger型。

Relationship的关系:

以1号Relationship为例,MyClass这个Entity有一个叫students的Relationship,表示这个班级里有哪些学生,一个MyClass中有若干个Student,所以是To Many的关系,即一对多,删除班级后,对应的学生也要被删除,所以删除规则是Cascade。

另外还要给Relationship设置Inverse,即反向关系,若不指定会有warning。还是以序号1为例,一个MyClass包括哪些Student,反过来就是一个Student属于哪个MyClass,很明显,1号的Inverse就是6号。

弄好后将Editor Style设置为Graph,如下图:

这个自动生成的图还是蛮直观的,单箭头代表“一”,双箭头代表“多”,如Teacher和Course之间的关系就是“一Teacher对多个Course”的关系。

还有一步,就是生成MO的子类,新建文件,选择CoreData中的NSManagedObject subclass:

Next,选中,Next,全选中,Create,这四个Entity的subclass就生成了,它们派生自NSManagedObject。

五、要不要“三层架构”

“三层架构”恐怕是我们听得最多,用得最多,但到最后却往往因为要依循它而作茧自缚的东西,其实关于“三层架构”的理解我见过N个版本,其中见得最多的版本就是这三层:“UI层”,“业务逻辑层”和“数据访问层”。数据访问层直接访问数据库,负责对表的简单增删查改,如果业务逻辑就是对表的增删查改的话,那业务逻辑层基本什么都不用干,我想你能在网上找到的例子大多如此,更有一些代码生成工具,直接帮你根据你的表结构生成这“三层架构”,其实我认为这是“帮倒忙”,徒增一大堆垃圾代码。

根据我的实战经验,所谓三层,大多时候都只需要两层,即UI层和业务逻辑层,而数据访问层则归入业务逻辑层去,因为这两者密不可分,数据就是业务,业务就是数据。理论上来说,你将业务逻辑层和数据访问层分开,能做到在更换DBMS的时候,业务逻辑层不需要修改,但实际上这种事情百年不遇,更换DBMS绝对是伤筋动骨的事情,如果遇到,那基本上就是一切推倒重来了。

好,言归正传,我们在使用CoreData的时候到底需不需要分层,我认为不用,因为CoreData其实并不是一套ORM,前面说了,它是一套很直接了当的图形化的对象关系及持久化框架,对象直接呈现在你的界面上,存在于你的内存中,而对象是怎么存储在sqlite中的,你基本不用关心。如果把MO一定要归入数据访问层,其上层无法接触到的话,那么要增加不少代码,你得把MO转为你自己定义的OC对象,而且你这么一来,就没法方便地用到CoreData所提供的一些特性,如NSFetchedResultController,总而言之是很不方便。

如果前面讲的仅仅是“不方便”,那这点恐怕就是“大麻烦”,那就是你不得不维护一个ID,前面我们创建的这些实体,大家看有没有ID?没有对吧,因为CoreData会在内部帮我们创建好ID,一般情况下,我们根本不需要关心各个实体的ID是什么,因为我们都是直接获取实体并使用,没有说“帮我获取到ID为多少多少的实体”,如果你硬要把Managed Object们限制在数据访问层中,那么你要在你自定义的OC对象中放入一个ID,以此来创建跟Managed Object的对应关系,这不得不说是个大麻烦。如果你真打算这么干,那下文我也会提到如何获取到这个ID的方法。但我真的不推荐。

如果你需要的是比较复杂的业务逻辑,而不是简单的“持久化”,那么CoreData可能并不适合,这时候你可以根据自己的需求,去选择直接使用Sqlite或者别的方案了。
六、写一个管理类

虽然不需要分层,但我们还是需要这么一个管理类来让我们的代码更好看一些,我们尽量把CoreData的各种操作,放在这个管理类中,在我们这个小小的应用中,只需要这么一个单实例的管理类即可。
复制代码

//CollegeManager.h@interface CollegeManager : NSObject
+ (CollegeManager*)sharedManager;
- (void)save;
- (void)deleteEntity:(NSManagedObject*)obj;
@end//CollegeManager.m#import "CollegeManager.h"
#import "AppDelegate.h"static CollegeManager* _sharedManager = nil;@implementation CollegeManager{AppDelegate* appDelegate;NSManagedObjectContext* appContext;
}+ (CollegeManager*)sharedManager{static dispatch_once_t once;dispatch_once(&once, ^{_sharedManager = [[self alloc] init];});return _sharedManager;
}- (id)init{self = [super init];appDelegate = [[UIApplication sharedApplication] delegate];appContext = [appDelegate managedObjectContext];return self;
}- (void)save{[appDelegate saveContext];
}- (void)deleteEntity:(NSManagedObject*)obj{[appContext deleteObject:obj];[self save];
}
@end

目前自有一个save和一个deleteEntity方法,之后再根据需要一点点加。
七、加一些实体并指定它们的关系

准备工作做好了,我们要开始用了,如果要做一个带完整界面的demo,这需要大量的工作,估计讲界面创建的篇幅会远超CoreData,但本文的主题是CoreData,而不是如何做界面,所以还是直接拖几个button,执行几个动作,NSLog一些东西出来就行了。当然,在后面讲到NSFetchedResultContoller的时候,会有一个相对完整的界面。

好,我们往前面做的那个管理类中加一个方法,initData,即加数据,下面的代码都有很完整的注释,我想不需要太多解释了:

-(void)initData
{//插入一些班级实体//这个Mutable Array是为了方便后面建立实体关系使用(后面的也是)NSMutableArray* arrMyClasses = [[NSMutableArray alloc] init];NSArray* arrMyClassesName = @[@"99级1班",@"99级2班",@"99级3班"];for (NSString* className in arrMyClassesName) {MyClass* newMyClass = [NSEntityDescription insertNewObjectForEntityForName:@"MyClass" inManagedObjectC

IOS CoreData相关推荐

  1. iOS coredata 多表查询

    先创建几个表. 1.部门表:department dp_id  Integer primary key dp_deptname  varchar(20) //使用coredata实体创建时用strin ...

  2. iOS CoreData (一) 增删改查

    代码地址如下: http://www.demodashi.com/demo/11041.html Core Data是iOS5之后才出现的一个框架,本质上是对SQLite的一个封装,它提供了对象-关系 ...

  3. iOS CoreData简单入门 - Swift版

    CoreData --- Swift 1,创建IOS项目并选择使用CoreData,选择语言Swift 2,打开项目目录 会有一项 CoreDataDemo.xcdatamodeld ,打开它,添加 ...

  4. IOS CoreData 简单使用CURD

    2019独角兽企业重金招聘Python工程师标准>>> iOS在CoreData中简单封装了SQLite,让开发者不需要写sql语句就可以使用SQLite进行CURD操作. 要使用C ...

  5. IOS: CoreData

    本篇主要介绍IOS Swift 中CoreData的基本用法和一些自己的理解 CoreData是一个数据库框架,可以让在app上本地存储一些数据,也有数据库基本的增删改查功能 CoreData有三部分 ...

  6. iOS - CoreData了解和简单应用

    core data是一种本地数据存储方式,和archiver,sqllite的作用差不多 CoreData主要目的是简化开发离线体验的成本,它抽象了设备的本地存储API,应用方向当然是为App提供离线 ...

  7. ios CoreData的使用(封装)

    本文讲解CoreData的使用,封装: 文章末尾附有demo 一.CoreData的简单理解 CoreData是一个模型层的技术,也是一种持久化技术,它能将模型对象的状态持久化到磁盘里,我们不需要使用 ...

  8. ios: coreData的NSManagedObject setvalue为null

    当用到coredata的时候,当你存数据: NSManagedObject *oneObject = [NSEntityDescriptioninsertNewObjectForEntityForNa ...

  9. iOS CoreData版本升级和数据库迁移

    2018年10月24日 10:20:00 https://blog.csdn.net/weixin_34168700/article/details/86021876 app中使用了CoreData, ...

  10. iOS CoreData的使用

    CoreData是一个专门管理数据服务的框架,把OC对象和存储在SQLite文件中的数据进行互相转换,极大地方便了开发者在数据服务方面的开发. 1. 创建CoreData 在文件创建区下,选择[Cor ...

最新文章

  1. 【经验】【ORACLE】从字符串中截取其中的数字
  2. MySQL案例-多源复制引起的内存泄漏
  3. 波士顿动力新年视频第一发,机器人狗能为朋友开门了!
  4. 【笨嘴拙舌WINDOWS】字符类型与字符串
  5. 金融实战篇:最佳数据驱动之城商行
  6. Qt创建工程及导入资源图片
  7. js - 执行上下文和作用域以及闭包
  8. Java 解析 XML
  9. java setr()_Java RPr.setRFonts方法代码示例
  10. Python使用numpy和pandas模拟转盘抽奖游戏
  11. Pandas DataFrame 去重
  12. [Bzoj2120]数颜色
  13. xp访问计算机组提示没有权限,WindowsXP系统提示没有权限使用网络怎么办
  14. 浏览器地址栏中文乱码问题
  15. Google Bard vs. ChatGPT 哪家强?结果一目了然
  16. go语言 | jwt鉴权初涉
  17. 配置接口IP地址并通过静态路由、默认路由配置实现全网互通!
  18. SonarQube代码质量扫描持续集成
  19. C语言结构体复习(一)
  20. Windows 10 21H1 更新的3种方式

热门文章

  1. 游离态GLZ的LeetCode刷题笔记2
  2. 小程序获取dom节点方法总结
  3. vss2005和Myecilpse的集成
  4. 超全!9种PCB表面处理工艺大对比
  5. 教你写出高质量SQL(实践必备)
  6. linux awk 设置换行符,shell – awk / sed替换换行符
  7. 别再小看硬件防火墙了!一些关于防火墙的小知识。
  8. Fragment懒加载——最简方案(LazyBread)
  9. 新时尚Windows8开发(15):扩展联系人选择器
  10. linux fwrite 头文件,linux的fwrite()使用方法