文档章节

iPhone开发之CoreData(基础篇)

jackyyang
 jackyyang
发布于 2012/07/29 10:56
字数 1176
阅读 2895
收藏 5

通过上一篇iPhone开发之SQLite的学习,基本学会了 SQLite在iPhone中的使用,这时候我就在找有没有SQLite的封装类,这样可以避免自己重复地SQLite的封装代码,Google一下,找 到几个objc-sqlite、FMDB等,还有一些其它不知名的封装库,官方也提供了CoreData框架来提供完整的对象持久化存储方案,还是有必要 要学习一下。

基本概念

在CoreData有一些概念刚学习的时候不是很容易理解,还是要单独拿出来来梳理一下,这样学后面的内容不会感觉吃力。

coredata terminology

图1

从图1中我们可以看到,在数据库结构中的一些术语,在这里会有对应,但不是全部。

  • ♥ 表结构:NSEntityDescription
  • ♥ 表记录:NSManagedObject

coredata aps

图2

从图2中我们可以看到一些数据库操作方面的一些术语

  • ♥ 数据库存放方式:NSPersistentStoreCoordinator(持久化存储协调者)
  • ♥ 数据库操作:NSManagedObjectContext(被管理的对象上下文)

还有一些类NSManagedObjectModel、NSFetchRequest什么的,具体项目就会有体会,下面来实战一下。

新建一个项目,项目模板基于“Master-Detail Application”,点击“Next”按钮,项目命名为“SimpleCoreData”,并勾选“Use Core Data”,点击“Next”,选择项目保存的目录,点击“Create”按钮,项目创建完毕。

SimpleCoreData SimpleCoreData xcodeproj

图3

代码分析

比以前创建的简单项目多了不少代码,还有xcdatamodeld文件,慢慢分析代码,AppDelegate.h头文件中,添加了三个property

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

再分析AppDelegate.m文件,有对应的三个方法来返回各自对应的对象

#pragma mark - Core Data stack  - (NSManagedObjectContext *)managedObjectContext{ ...
    return __managedObjectContext;}  - (NSManagedObjectModel *)managedObjectModel{ ...  
    return __managedObjectModel;}  - (NSPersistentStoreCoordinator *)persistentStoreCoordinator{ ...
    return __persistentStoreCoordinator;}

这些对象在哪里被调用的呢,打开MasterViewController.m,在初始化函数中,我们看到通过获取delegate,再通过 delegate调用方法managedObjectContext,这样就得到了这个NSManagedObjectContext对 象,NSManagedObjectContext对象它会跟NSPersistentStoreCoordinator对象打交 道,NSPersistentStoreCoordinator会去处理底层的存储方式。

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{     self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {         self.title = NSLocalizedString(@"Master", @"Master");
        id delegate = [[UIApplication sharedApplication] delegate];
        self.managedObjectContext = [delegate managedObjectContext];
    }     return self;}

查询实体

分析MasterViewController.m的代码发现以下函数的调用顺序。

  • ♥ -tableView:(UITableView *)tableView cellForRowAtIndexPath:
  • ♥ -configureCell:atIndexPath:
  • ♥ -fetchedResultsController

最后是从fetchedResultsController获取到查询结果,那就有必要来分析一下

- (NSFetchedResultsController *)fetchedResultsController{     // 如果查询结果已经存在就直接返回__fetchedResultsController     if (__fetchedResultsController != nil)     {         return __fetchedResultsController;
    }  
    // 1.创建NSFetchRequest对象(相当于SQL语句)     NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
 
    // 2.创建查询实体(相当于设置查询哪个表)     NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];
 
    // 设置获取数据的批数.     [fetchRequest setFetchBatchSize:20];
 
    // 3.创建排序描述符,(ascending:是否升序)     NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timeStamp" ascending:NO];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
 
    [fetchRequest setSortDescriptors:sortDescriptors];
 
    // 根据fetchRequest和managedObjectContext来创建aFetchedResultsController对象,并设置缓存名字为"Master".     NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:@"Master"];
 
    // 设置aFetchedResultsController的委托对象为当前类     aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;
 
	NSError *error = nil;
    // 获取第一批数据 	if (![self.fetchedResultsController performFetch:&error])         {         // 错误处理 	    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
	    abort();
	}  
    return __fetchedResultsController;}

因为我们设置了aFetchedResultsController的委托NSFetchedResultsControllerDelegate,就要实现它的方法,幸运的是这些方法看起来都像下面这样,直接复制粘贴就行了。

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller{     [self.tableView beginUpdates];}  - (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
           atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type{     switch(type)     {         case NSFetchedResultsChangeInsert:             [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
 
        case NSFetchedResultsChangeDelete:             [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
    } }  - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath *)newIndexPath{     UITableView *tableView = self.tableView;
 
    switch(type)     {  
        case NSFetchedResultsChangeInsert:             [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
 
        case NSFetchedResultsChangeDelete:             [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
 
        case NSFetchedResultsChangeUpdate:             [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
            break;
 
        case NSFetchedResultsChangeMove:             [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]withRowAnimation:UITableViewRowAnimationFade];
            break;
    } }  - (void)controllerDidChangeContent:(NSFetchedResultsController *)controller{     [self.tableView endUpdates];}

添加实体

- (void)insertNewObject{     // 从NSFetchedResultsController中获取NSManagedObjectContext对象     NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
 
    // 从NSFetchedResultsController中获取实体描述     NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
 
    // 在被管理上下文中插入一个新的NSManagedObject     NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
 
    // 字段赋值     [newManagedObject setValue:[NSDate date] forKey:@"timeStamp"];
 
    // 保存被管理对象上下文,这样刚才的newManagedObject就被保存了     NSError *error = nil;
    if (![context save:&error])     {         // 错误处理.         NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    } }

删除实体

// 从NSFetchedResultsController中获取NSManagedObjectContext对象 NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
 // 从被管理对象上下文中删除MO对象 [context deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]];
 // 保存被管理对象上下文 NSError *error = nil;if (![context save:&error]) {     // 错误处理     NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();}

这个删除对象为什么没有处理TableView的代码,因为我们实现NSFetchedResultsControllerDelegate委托,当对象上下文发生变化时NSFetchedResultsControllerDelegate的实现方法会处理这些事情。

© 著作权归作者所有

共有 人打赏支持
jackyyang
粉丝 22
博文 42
码字总数 18506
作品 0
珠海
私信 提问
iOS:在AppDelegate中定义managed object context

关于core data 的,我之前已经做了好多小结 Core Data ---这篇介绍了core data的一些架构及基本实现; iphone开发中的数据存储:Core Data ----这篇介绍了存储四个textField的例子。从appde...

吞吞吐吐的
2017/10/10
0
0
iPhone开发之CoreData(实战篇)

iPhone开发之CoreData(基础篇)中已经学习了CoreData的理论基础,是基于“Master-Detail Application”项目的代码分析,这一篇直接进入实战。 我们从“Empty Application”一个空项目开始,命...

jackyyang
2012/07/29
0
0
CocoaTouch框架

iPhoneOS应用程序的基础CocoaTouch框架重用了许多Mac系统的成熟模式,但是它更多地专注于触摸的接口和优化。UIKit为您提供了在iPhoneOS上实现图形,事件驱动程序的基本工具,其建立在和MacOS...

hi-小疯疯
2015/11/30
463
0
第三方开源框架(你了解的ios只是冰山一角)总能找到要用的

补充一个链接 使用搜索找到你需要的内容吧,相当丰富的合集。 原文相当多,现在展示个冰山一角 sstoolkit 一套Category类型的库,附带很多自定义控件 功能不错~ BlocksKit 将Block风格带入U...

iShown
2016/01/22
233
0
Swift实践:使用CoreData完成上班签到小工具

image.png 之前在前两篇里面实现了一个十分简陋的通讯录,而且都是通过系统默认的方式创建的CoreData。可是实际中哪里有那么好的事情嘛,要是忘记在创建工程的时候勾选了下面这个图怎么办? ...

非典型技术宅
2017/12/03
0
0

没有更多内容

加载失败,请刷新页面

加载更多

winscp中使用sudo的方法

用截图了解如何在 WinSCP 中使用 sudo。 首先你需要检查你尝试使用 WinSCP 连接的 sftp 服务器的二进制文件的位置。 你可以使用以下命令检查 SFTP 服务器二进制文件位置: [root@kerneltalk...

Linux就该这么学
35分钟前
1
0
四、MyBatis中查询执行流程

一、查询执行大致流程 在MyBatis中,查询执行的大致流程如下:

yangjianzhou
41分钟前
1
0
系统幂等设计

前言 幂等简单的定义: 系统中的多次操作,不管多少次,都应该产生一样的效果,或返回一样的效果。 比如实际的业务请求为创建一个活动,理论上需要根据业务形态开发幂等创建活动的接口,这样...

春哥大魔王的博客
今天
5
0
DevSecOps 运维模式中的安全性

导读 本文想从技术的角度谈谈我对云计算数据中心 DevSecOps 运维模式中的安全性的理解,和过去几年我在云服务业务连续性管理方面的探索。 现在公有云服务商都不约而同地转向 DevSecOps 模式。...

问题终结者
今天
1
0
java 基础脑图 转载来的

NotFound403
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部