文档章节

CoreData (三)

独-奏
 独-奏
发布于 2014/02/13 18:30
字数 1279
阅读 190
收藏 1

NSFetchedResultsController

什么是NSFetchedResultsController

NSFetchedResultsController是一个让人爱恨交加的一个类。如果使用得当,NSFetchedResultsController能帮组减少很多代码。如果使用不当,整个App就随时崩溃。

NSFetchedResultsController我觉得最初的设计应该是为了配合UITableView来使用的。因为UITableView在iOS的应用App中出场次数实在是太高了.而且UITableView是重要的数据展示View,所以需要频繁的向Model去请求数据,但是根据MVC来说,V不应该直接跟M联系的.这样就在Core Data下面出现了一个C—NSFetchedResultsController来把V和M协调起来. NSFetchedResultsController就是这个C.

NSFetchedResultsController是有两个重要的功能。

第一:NSFetchedResultsController是作用在Core Data上的,通过NSFetchRequest来查询Core Data里面的数据.可以返回按照组分好的数据.这样便于UITableView来显示.

第二:但Modle改变的时候NSFetchedResultsController能及时的发出通知.准确的说,应该是当NSManagedObjectContext发生改变的时候,NSFetchedResultsController能知道这些变化,然后发出通知出来.以便UITableview能及时的更新.

实现一个NSFetchedResultsController作为Data source的UITableView

创建一个最小带Core Data的工程

选择Master-Detail Application

整理一下显示层级和结构使其看起来顺眼一些

确立目标

打开看以后 发现建立的工程是已经使用了NSFetchedResultsController
我们的目标是改写这个项目支持UITableView分组显示

首先修改Data Model

增加一个字段用来分组. 我们增加一个同样的Date用来记录此时的分钟数量.

初始化一个NSFetchedResultsController

这里假设你看过我的Core Data笔记1,2.默认你已经做好了Core Data stack的全部工作.然后再开始NSFetchedResultsController的初始化.

- (NSFetchedResultsController *)fetchedResultsController
{    if (_fetchedResultsController != nil) {        
        return _fetchedResultsController;
    }

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    // Edit the entity name as appropriate.
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:self.managedObjectContext];
    [fetchRequest setEntity:entity];

    // Set the batch size to a suitable number.
    [fetchRequest setFetchBatchSize:20];

    // Edit the sort key as appropriate.
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timeStamp" ascending:NO];
    NSArray *sortDescriptors = @[sortDescriptor];

    [fetchRequest setSortDescriptors:sortDescriptors];

    // Edit the section name key path and cache name if appropriate.
    // nil for section name key path means "no sections".
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"sectionMinute" cacheName:@"Master"];
    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;

    NSError *error = nil;    
    if (![self.fetchedResultsController performFetch:&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();
    }
    return _fetchedResultsController;
}

这里是工程里面的NSFetchedResultsController的set方法.可以看出,第一我们创建一个NSFetchRequest查询.然后在用这个NSFetchRequest去创建一个NSFetchedResultsController.

NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"sectionMinute" cacheName:@"Master"];

第一个参数就是NSFetchRequest.

第二个参数是要指定在哪个context里面进行查询

第三个参数是根据什么key来分组.sectionNameKeyPath本来是nil是不分组,我改为我们需要分组的key值“sectionMinute”.

第四个参数 官方解释是这里点到The Cache的地方. 我的理解是cache只保留很少的一部分数据在磁盘上面,如果使用了Cache,在重建UITableView的时候, 就优先查询cache里面的数据.然后要在-performFetch:执行的时候才会去刷新新的数据.这样有助于UITableView的流畅性.

然后我加入Sections的方法

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    NSArray *sections = [[self fetchedResultsController] sections]; id <NSFetchedResultsSectionInfo> sectionInfo = nil;
    sectionInfo = [sections objectAtIndex:section];
    
    return [sectionInfo name];
}

接着我添加

https://github.com/erica/NSDate-Extensions.git

这个NSDate库进来.自己按照他的写法,写一个能获得当前时间秒数为0的方法.用来分组.

- (NSDate *) dateAtStartOfMinutes
{    NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:self];
	[components setSecond:0];
	return [CURRENT_CALENDAR dateFromComponents:components];
}

然后改写insert方法

- (void)insertNewObject:(id)sender
{
    NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
    NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];
    NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];
    
    // If appropriate, configure the new managed object.
    // Normally you should use accessor methods, but using KVC here avoids the need to add a custom class to the template.
    [newManagedObject setValue:[NSDate date] forKey:@"timeStamp"];
    [newManagedObject setValue:[[NSDate date] dateAtStartOfMinutes]  forKey:@"sectionMinute"];
    
    // Save the context.
    NSError *error = nil;    if (![context 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();
    }
}

其实就是加入了

[newManagedObject setValue:[[NSDate date] dateAtStartOfMinutes]  forKey:@"sectionMinute"];

这句.

这样,简单的使用NSFetchedResultsController来显示分组的UITableView就搞定了.
当然因为建立的工程模板原因.很大一部分都是xCode搞定的.

被遗忘的地方

Sections数量,决定了有多少组

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{    return [[self.fetchedResultsController sections] count];
}

如果在初始化NSFetchedResultsController的时候sectionNameKeyPath为nil.这里应该会返回1.(就算没有数据也会返回1)

Row数量,决定每一组分别有多少行数据.

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{    id <NSFetchedResultsSectionInfo> sectionInfo = [self.fetchedResultsController sections][section];    
    return [sectionInfo numberOfObjects];
}

我前面说过NSFetchedResultsController就是为了配合UITableView而设计的.所以自然有根据indexPath来取对应的NSManagedObject的方法.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{    
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
    [self configureCell:cell atIndexPath:indexPath];    
    return cell;
}

- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
    NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
    cell.textLabel.text = [[object valueForKey:@"timeStamp"] description];
}

show

总结

写Blog实在是太累了. NSFetchedResultsController努力一天也才一点点.回去继续写. 下次要写NSFetchedResultsController通知方法.


本文转载自:http://iiiyu.com/2013/04/17/learning-ios-notes-twenty-one/

上一篇: CoreData (四)
下一篇: Core Data (二)
独-奏

独-奏

粉丝 15
博文 37
码字总数 31176
作品 6
蓬莱
程序员
私信 提问
iOS中CoreData数据管理系列三——添加与查询数据

iOS中CoreData数据管理系列三——添加与查询数据 一、引言 在前两篇博客中,分别介绍了iOS中CoreData框架创建数据模型和CoreData框架中的三个核心类。博客地址如下: iOS中CoreData框架简介:...

珲少
2016/01/29
1K
0
CoreData 使用

一、CoreData的简单使用 准备工作 创建数据库 新建文件,选择 -> 添加实体(表), 给表中添加属性,点击下方的‘+’号 创建模型文件 新建文件,选择 -> 根据提示,选择实体 通过代码,关联数...

Jack088
2016/02/04
18
0
Core Data 学习笔记 常用链接整理

目录 Core Data 学习笔记(一)框架简介 Core Data 学习笔记(二)被管理对象模型 Core Data 学习笔记(三)被管理对象 Core Data 学习笔记 应用示例 Core Data 学习笔记 常用链接整理 文章 ...

灰大羊
2015/07/31
0
0
iOS中CoreData数据管理系列四——进行数据与页面的绑定

iOS中CoreData数据管理系列四——进行数据与页面的绑定 一、引言 在上一篇博客中,我们讨论了CoreData框架中添加与查询数据的操作,事实上,在大多数情况下,这些数据都是由一个UITableView...

珲少
2016/02/01
886
0
iOS中CoreData数据管理系列二——CoreData框架中三个重要的类

iOS中CoreData数据管理系列二——CoreData框架中三个重要的类 一、引言 在上一篇博客中,介绍了iOS中使用CoreData框架设计数据模型的相关步骤。CoreData框架中通过相关的类将数据——数据模型...

珲少
2016/01/28
855
0

没有更多内容

加载失败,请刷新页面

加载更多

在Javascript中Eval函数的使用

【eval()函数】 JavaScript有许多小窍门来使编程更加容易。 其中之一就是eval()函数,这个函数可以把一个字符串当作一个JavaScript表达式一样去执行它。 举个小例子: var the_unevaled_ans...

花漾年华
12分钟前
1
0
[日更-2019.5.22、23] Android 系统的分区和文件系统(二)--Android 文件系统中的文件

声明 Android系统中有很多分区,每个分区内的文件系统一般都不同的,使用ADB进入系统/目录下可发现挂载这很多的目录,不同的目录中可来自不同的分区及文件系统; 那么,就来分下这些目录里面...

小馬佩德罗
16分钟前
2
0
数组操作相关算法

/*数组的相关的算法操作:1、在数组中找最大值/最小值*/class Test11_FindMax{public static void main(String[] args){int[] array = {4,2,6,8,1};//在数组中找最大...

architect刘源源
今天
2
0
okhttp3 以上版本在安卓9.0无法请求数据的解决方案

应用官方的说明:在 Android 6.0 中,我们取消了对 Apache HTTP 客户端的支持。 从 Android 9 开始,默认情况下该内容库已从 bootclasspath 中移除且不可用于应用。且Android P 限制了明文流量...

chenhongjiang
今天
12
0
简单示例:NodeJs连接mysql数据库

开篇引用网上的说法: 简单的说 Node.js 就是运行在服务端的 JavaScript。Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台。Node.js是一个事件驱动I/O服务端JavaScript环境,基于...

李朝强
今天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部