上面一篇文章介绍了coredata的有关基本概念,由于大部分是参考别人文章中的内容,所以感觉有点虚,而且估计也是比较难以理解,下面这篇文章通俗一点说说学习coredata后的一些理解,然后给出一个简单的demo,有错漏的地方,欢迎读者指正。

其实与coredata有关的有几个概念:

  • 数据表 --–> Entity  (You usually define entities in a managed object model usingthe data modeling tool in Xcode).
  • 表格的记录 --> NSManagedObject (一个表记录就是一个NSManagedObject实例)
  • 描述表格结构 --> NSEntityDescription
  • 数据库中所有表格和他们的联系 -->NSManagedObjectModel
  • 数据库存放方式 --> NSPersistentStoreCoordinator
  • 数据库操作 --> NSManagedObjectContext
  • 查询语句 --> NSFetchRequest

下面依次讲解一下:

(1)Entity,实体。这个是数据表,也就是你在xcode中可视化编辑的那个东西。它含有Attributes,Relationship和Fetched Property三个属性,其中叫常用的是前两个属性。如下图,就是包含了两个实体(DeviceItem和ImageData),每个实体都含有Attributes,Relationship。

所以可以这样理解,实体就是一个抽象的数据表

(2)Managed Object,托管对象。是对于Entity实体的模型文件,它有一个基类NSManagedObject,所以的模型文件都是继承NSManagedObject而来。那么我们对应上面说到的两个实体,就可以对应的创建两个模型文件。如下图:

这些模型文件其实就是继承NSManagedObjectd的类那么以后我们要添加一条记录或者删除一个记录,那么操作的对象就是这些类的实例对象,也就是说一个记录就是一个NSManagedObject实例。

注意到在这些文件中对属性使用的是@dynamic修饰,如在DeviceItem.m文件中

  1. @dynamic iD;
  2. @dynamic imageURL;
  3. @dynamic link;
  4. @dynamic title;
  5. @dynamic image;

那么@dynamic和@synthesize有什么区别呢

在声明property属性后,有2种实现选择

@synthesize

编译器期间,让编译器自动生成getter/setter方法。

当有自定义的存或取方法时,自定义会屏蔽自动生成该方法

@dynamic

告诉编译器,不自动生成getter/setter方法,避免编译期间产生警告

然后由自己实现存取方法或存取方法在运行时动态创建绑定:主要使用在CoreData的实现NSManagedObject子类时使用,由Core Data框架在程序运行的时动态生成子类属性

 
(3)NSEntityDescription,实体描述显然这个就是用来描述实体的,它包含的内容就包括实体的属性,关系等信息,我们通过NSEntityDescription就可以了解实体,那么通过这个NSEntityDescription,我们就可以创建对应实体的Managed Object。所以说,它是用来描述表的结构的。

(4)NSManagedObjectModel,托管对象模型。模型由多个实体描述对象Entity Description构成。通过下图就可以知道什么是托管对象模型了。

(5)NSPersistentStoreCoordinator,持久化存储管理的助理,它是用来负责数据存储的方式的,我们知道coredata的数据存储方式可以有多种SQLite3数据库、二进制文件、XML文件,那么它就是负责这部分内容的。

(6)NSManagedObjectContext,简称是上下文。通过下面这张图应该可以了解上下文的作用了,所以的Managered Object都要在上下文中登记注册,那么你对Managered Object进行操作后,通过上下文就可以进行保存修改,也就说通过上下文进行对数据库数据的以一些操作。

(7)NSFetchRequest ,获取数据的请求,我们要想从上下文中获取到数据,首先还要创建数据请求。创建请求过程中可以指定一些参数,首先是实体,每次获取数据只能指定一种实体,也即指定一种数据表类型,这时候要传入的参数当然就是Entity Description啦;其次还要指定NSPredicate,谓词,也就是限定条件,只有满足条件的数据才被返回;还可以指定排序条件NSSortDescriptor,即按照某个数据项进行升序或者降序的排列。

注意:①其中指定参数中的第一个实体是必须的,而后两个NSPredicate和NSSortDescriptor则是可选的,如果不指定NSPredicate,那么返回的是该实体所描述的所有Managered Objects。

关于如何撰写NSPredicate,这里有详细的介绍:

https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Predicates/Articles/pSyntax.html

②获取数据请求返回的数据是以数组的形式,如果指定了排序条件,那么这些数据就会按某个数据项有序返回。

通过下面这种图也可以较形象的理解:

最后再附上两张图片可以对CoreData有一个整体的认识和弄清之间的关系

下面开始讲一下这个小demo。

(1)我们通过建立一个master-detail工程(勾选使用CoreData)那么在AppDelegate中就回生成一些CoreData操作中必须的一些方法和属性。如下:

  1. @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
  2. @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel;
  3. @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator;
  4. - (void)saveContext;
  5. - (NSURL *)applicationDocumentsDirectory;
  1. @synthesize managedObjectContext = _managedObjectContext;
  2. @synthesize managedObjectModel = _managedObjectModel;
  3. @synthesize persistentStoreCoordinator = _persistentStoreCoordinator;
  4. //通过context上下文保存coredata中的数据内容
  5. //这个方法的通常是在应用程序退出或者推入后台时调用
  6. - (void)saveContext
  7. {
  8. NSError *error = nil;
  9. NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
  10. if (managedObjectContext != nil) {
  11. if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
  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. NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
  15. abort();
  16. }
  17. }
  18. }
  19. #pragma mark - Core Data stack
  20. // Returns the managed object context for the application.
  21. // If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
  22. - (NSManagedObjectContext *)managedObjectContext
  23. {
  24. if (_managedObjectContext != nil) {
  25. return _managedObjectContext;
  26. }
  27. NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
  28. if (coordinator != nil) {
  29. _managedObjectContext = [[NSManagedObjectContext alloc] init];
  30. [_managedObjectContext setPersistentStoreCoordinator:coordinator];
  31. }
  32. return _managedObjectContext;
  33. }
  34. // Returns the managed object model for the application.
  35. // If the model doesn't already exist, it is created from the application's model.
  36. - (NSManagedObjectModel *)managedObjectModel
  37. {
  38. if (_managedObjectModel != nil) {
  39. return _managedObjectModel;
  40. }
  41. NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"CoreDataDemo" withExtension:@"momd"];
  42. _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
  43. return _managedObjectModel;
  44. }
  45. // Returns the persistent store coordinator for the application.
  46. // If the coordinator doesn't already exist, it is created and the application's store added to it.
  47. - (NSPersistentStoreCoordinator *)persistentStoreCoordinator
  48. {
  49. if (_persistentStoreCoordinator != nil) {
  50. return _persistentStoreCoordinator;
  51. }
  52. NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreDataDemo.sqlite"];
  53. NSError *error = nil;
  54. _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
  55. if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
  56. NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
  57. abort();
  58. }
  59. return _persistentStoreCoordinator;
  60. }
  61. #pragma mark - Application's Documents directory
  62. // Returns the URL to the application's Documents directory.
  63. - (NSURL *)applicationDocumentsDirectory
  64. {
  65. return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
  66. }

以上这部分代码是通用的,可以直接将这部分的内容转到你的Controller中,这样方法的调用都比较简单;当然你也可以在controller中通过delegate获取到这些方法,进行调用,如下所示(注意要#import "AppDelegate.h"):

  1. AppDelegate *myDelegate = [[UIApplication sharedApplication] delegate];

还有一个要说明的是saveContext这个方法的使用,上面的注释中已经有说明使用的情形,例如在AppDelegate中,

  1. - (void)applicationWillTerminate:(UIApplication *)application
  2. {
  3. // Saves changes in the application's managed object context before the application terminates.
  4. [self saveContext];
  5. }

那么假如我们把这些内容转移放到控制器中,那么就可以在添加一个程序推到后台的通知响应,在响应事件的处理中调用这个方法,那么就可以起到保存数据的作用。

说明:最好不要将这些这些coredata操作有关的内容转移到你的controller中,对于小 demo来说是没有问题的,那么如果是对于大一些的工程来说,肯定不是一个controller使用到这些方法,所以还是不做转移好,要使用的地方创建一个AppDelegate实例进行方法调用就好了。

但是下面我讲到的demo中,还是复制了一份到controller中,为的是调用方便。

(2)首先简单介绍这个demo:这个demo会根据一个URL下载一些有关手机的JSON数据,解析后显示在tableview中,而且会保存到coredata中,下一次启动应用程序的时候检测到coredata中有数据就可以不用下载,直接获取数据对tableview进行load数据操作。而且在视图还有一个Fetch按键,用于获取指定的数据内容的操作,然后在终端中显示出来。

该demo中包含两个实体:

下面只显示一些与coredata操作的关键代码,其余部分请下载完整程序代码:下载地址

  1. //初始化上下文
  2. NSManagedObjectContext *context = [self managedObjectContext];
  3. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  4. //首先查询coredata中是否存在数据,如果存在数据,那么就不用下载数据了,直接用coredata中保存着的数据就可以了
  5. NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"DeviceItem" inManagedObjectContext:context];
  6. //不设置request的predicate,那么将返回coredata中所有的数据
  7. NSFetchRequest *request = [[NSFetchRequest alloc]init];
  8. [request setEntity:entityDescription];
  9. NSError *error = nil;
  10. NSArray *itemsArray = [context executeFetchRequest:request error:&error];
  11. //如果获取到的数组元素个数为0,则说明coredata中还没有数据,这时需要下载数据。
  12. if ([itemsArray count] == 0) {
  13. NSLog(@"下载数据中....");
  14. NSData* data = [NSData dataWithContentsOfURL: [NSURL URLWithString:@"http://course.gdou.com/Hw/Files/result.json"] ];
  15. NSError* error = nil;
  16. NSArray *items= [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
  17. if (error != nil)
  18. return;
  19. for(NSDictionary *d in items){
  20. // 创建一个新的Managed Object对象并插入到 context 中(尚未保存到数据库中)
  21. //            DeviceItem *di = [NSEntityDescription
  22. //                                               insertNewObjectForEntityForName:@"DeviceItem"
  23. //                                               inManagedObjectContext:context];
  24. // 创建Managed Object 对象的另一种方法:
  25. NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"DeviceItem" inManagedObjectContext:context];
  26. DeviceItem* di = [[DeviceItem alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:context];
  27. di.title=[d valueForKey:@"Title"];
  28. di.iD=[d valueForKey:@"ID"];
  29. di.link=[d valueForKey:@"Link"];
  30. di.imageURL=[d valueForKey:@"ImageURL"];
  31. ImageData *md=[NSEntityDescription
  32. insertNewObjectForEntityForName:@"ImageData"
  33. inManagedObjectContext:context];
  34. md.data=[NSData dataWithContentsOfURL:[NSURL URLWithString:di.imageURL]];
  35. // relations
  36. md.item=di;
  37. di.image=md;
  38. // 保存数据模型对象到数据库中
  39. [context save:&error];
  40. [self.allItems addObject:di];
  41. [self.allImages addObject:md];
  42. }
  43. }
  44. //否则,数组中存在元素,那么直接向tableview中load数据即可
  45. else{
  46. NSLog(@"从coredata中获取数据中...");
  47. for (DeviceItem *item in itemsArray) {
  48. //从coredata中获取到的数据初始化两个数组。
  49. [self.allItems addObject:item];
  50. [self.allImages addObject:item.image];
  51. }
  52. }
  53. dispatch_sync(dispatch_get_main_queue(), ^{
  54. block(nil);
  55. });
  56. });
  1. - (IBAction)fetchAction:(id)sender {
  2. NSManagedObjectContext *context = [self managedObjectContext];
  3. NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"DeviceItem" inManagedObjectContext:context];
  4. NSFetchRequest *request = [[NSFetchRequest alloc]init];
  5. [request setEntity:entityDescription];
  6. // 取出iD值以23197 起始的设备.
  7. // for Predicate Format String Syntax, see: https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Predicates/Articles/pSyntax.html
  8. NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K LIKE[c] %@",@"iD",@"23197?"];
  9. [request setPredicate:predicate];
  10. //按照iD的升序排列
  11. NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc]
  12. initWithKey:@"iD" ascending:YES];
  13. [request setSortDescriptors:@[sortDescriptor]];
  14. NSError *error = nil;
  15. NSArray *items = [context executeFetchRequest:request error:&error];
  16. //输出iD值以23197 起始的设备的个数。
  17. NSLog(@"count = %d",[items count]);
  18. //依次输出查询到的数据
  19. for (DeviceItem *item in items) {
  20. NSString *idString = item.iD;
  21. NSString *titleString = item.title;
  22. NSLog(@"id : %@,title = %@",idString,titleString);
  23. }
  24. }

大致就是以上的内容了,关于如何coredata的具体xcode操作,可以参考这篇文章 http://blog.csdn.net/q199109106q/article/details/8563438

我觉得应该讲清楚了,如有错漏的地方,欢迎读者指正。

ios之coredata(二)的更多相关文章

  1. XMPPFrameWork IOS 开发(二)- xcode配置

    原始地址:XMPPFrameWork IOS 开发(二) 译文地址:   Getting started using XMPPFramework on iOS 介绍 ios上的XMPPFramewor ...

  2. 微信连WiFi关注公众号流程更新 解决ios微信扫描二维码不关注就能上网的问题

    前几天鼓捣了一下微信连WiFi功能,设置还蛮简单的,但ytkah发现如果是ios版微信扫描微信连WiFi生成的二维码不用关注公众号就可以直接上网了,而安卓版需要关注公众号才能上网,这样就少了很多ios ...

  3. 【HELLO WAKA】WAKA iOS客户端 之二 架构设计与实现篇

    上一篇主要做了MAKA APP的需求分析,功能结构分解,架构分析,API分析,API数据结构分析. 这篇主要讲如何从零做iOS应用架构. 全系列 [HELLO WAKA]WAKA iOS客户端 之一 ...

  4. iOS runtime探究(二): 从runtime開始深入理解OC消息转发机制

    你要知道的runtime都在这里 转载请注明出处 http://blog.csdn.net/u014205968/article/details/67639289 本文主要解说runtime相关知识, ...

  5. 苹果IOS内购二次验证返回state为21002的坑

    项目是三四年前的老项目,之前有IOS内购二次验证的接口,貌似很久都没用了,然而最近IOS的妹子说接口用不了,让我看看啥问题.接口流程时很简单的,就是前端IOS在购买成功之后,接收到receipt后进行 ...

  6. iOS CoreData (二) 版本升级和数据库迁移

    前言:最近ChinaDaily项目需要迭代一个新版本,在这个版本中CoreData数据库模型上有新增表.实体字段的增加,那么在用户覆盖安装程序时就必须要进行CoreData数据库的版本升级和旧数据迁移 ...

  7. iOS:CoreData数据库的使用二(创建多个数据库表,表之间有对应关系)

    CoreData数据库框架是一个封装性好,功能强大数据库,它底层使用的还是sqlite数据库,不过苹果公司在其基础上,为其封装新和安全性的维护上做了大量的处理,例如对一些事物做了详细的操作,如读脏数据 ...

  8. iOS 让CoreData更简单些

    原文:http://www.cocoachina.com/ios/20170421/19096.html 前言 本文并不是CoreData从入门到精通之类的教程, 并不会涉及到过多的原理概念描述, 而 ...

  9. iOS开发CoreData的简单使用

    1.简介 CoreData是iOS5后,苹果提供的原生的用于对象化管理数据并且持久化的框架.iOS10苹果对CoreData进一步进行了封装,而且效率更高!相关类的简单介绍: NSManagedObj ...

随机推荐

  1. OPENGL_三角形带GL_TRIANGLE_STRIP详解

    使用三角形带原因:减少顶点传递,渲染时api向显卡传输数据量是瓶颈,用较好的传递方法传递一个三角形最少可以少于一个点. 点的顺序根据奇数,偶数不一样的原因:保持所有三角形法线在同一方向. 原文:htt ...

  2. [Xcode 实际操作]八、网络与多线程-(14)使用网址会话对象URLSession将地理坐标转换为地名

    目录:[Swift]Xcode实际操作 本文将演示如果通过网址会话对象,将地理坐标转换为地名. 网址会话对象URLSession具有在后台上传和下载.暂停和恢复网络操作.丰富的代理模式等优点. 在项目 ...

  3. [Xcode 实际操作]九、实用进阶-(23)多个Storyboard故事板中的页面跳转

    目录:[Swift]Xcode实际操作 本文将演示多个Storyboard故事板中的页面跳转. 使用快捷键[Command]+[N]创建一个新的故事板文件. (在项目文件夹[DemoApp]上点击鼠标 ...

  4. Oracle Java SE 组件概念图

    JDK1.8 组件概念图

  5. Cstring的使用

    https://msdn.microsoft.com/zh-cn/aa315043 1.字符串提取函数,CString::Left.CString::Mid .CString::Right CStri ...

  6. django (四) model模型

    models模型 1. models 定义属性 概述 django根据属性的类型确定以下信息 ·当前选择的数据库支持字段的类型 ·渲染管理表单时使用的默认html控件 ·在管理站点最低限度的验证 dj ...

  7. eShopOnContainers 是一个基于微服务的.NET Core示例框架

    找到一个好的示例框架很难,但不是不可能.大多数是小型Todo风格的应用程序,通常基于SimpleCRUD.值得庆幸的是,Microsoft已经为eShopOnContainers创建了一个基于微服务的 ...

  8. 530 Minimum Absolute Difference in BST 二叉搜索树的最小绝对差

    给定一个所有节点为非负值的二叉搜索树,求树中任意两节点的差的绝对值的最小值.示例 :输入:   1    \     3    /   2输出:1解释:最小绝对差为1,其中 2 和 1 的差的绝对值为 ...

  9. Codeforces Beta Round #12 (Div 2 Only) D. Ball 树状数组查询后缀、最值

    http://codeforces.com/problemset/problem/12/D 这里的BIT查询,指的是查询[1, R]或者[R, maxn]之间的最值,这样就够用了. 设三个权值分别是b ...

  10. CentOS7.2 yum安装报错

    1.yum源repodata配置文件repomd.xml无法找到: Couldn't open file /mnt/cdrom/repodata/repomd.xml 先找到repomd.xml的路径 ...