上面一篇文章介绍了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. 51nod1625(枚举&贪心)

    题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1625 题意:中文题诶- 思路:枚举+贪心 一开始写的行和列同时 ...

  2. IT兄弟连 JavaWeb教程 JSP内置对象1

    JSP内置对象定义 JSP提供了由容器实现和管理的内置对象,也可以称之为隐含对象,这些内置对象不需要通过JSP页面编写来实例化,在所有的JSP页面中都可以直接使用,它们起到了简化页面的作用,JSP的内 ...

  3. linux mysql乱码问题

    mysql,发现都是乱码,一堆问号,如下图: 查看mysql编码 需要修改mysql编码,打开/etc/my.cnf 文件 在下边添加如下行 [client] default_character_se ...

  4. java多线程模拟红绿灯案例

    代码Lighter.java: package pack1; /** * 灯线程 * @author Administrator * */ public class Lighter extends T ...

  5. jmeter diff测试

    1.准备接口数据(对比字段,即json数据中需要提取的key对应的值进行对比) 2.配置获取EXCEL数据 3.新建线程,并建两个http请求,分别用于请求新旧接口 4.提取需要对比的内容 5.赋值变 ...

  6. 牛客寒假5-A.炫酷双截棍

    链接:https://ac.nowcoder.com/acm/contest/331/A 题意: 小希现在手里有一个连着的两块木条,长度分别为l1l1,l2l2,木条之间有一个无摩擦的连接点,木条之间 ...

  7. 为VS中的括号添加虚线

    在VS中的扩展和更新中 安装Indent Guides插件,即可实现该功能.

  8. aix 推荐使用重启

    重启os AIX 主机 推荐 shutdown –Fr 在客户一次停机维护中,发现了这个问题. 环境是ORACLE 10G RAC for AIX6,使用了HACMP管理共享磁盘. 在停机维护时间段内 ...

  9. HackerRank Super Six Substrings dp

    https://www.hackerrank.com/contests/hourrank-18/challenges/super-six-substrings 能被6整除的数有一个特点,就是能同时被3 ...

  10. win10安装CAD后出现致命错误

    现在很多朋友在使用win10系统了,在win10系统打开cad却提示致命错误,这个时候应该怎么办呢?我们可以打开注册表编辑器然后找到某个注册表把数值改为0就可以解决这个问题了哦,下面就和小编一起来看看 ...