zoukankan      html  css  js  c++  java
  • CoreData (三)备

    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的初始化.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    - (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.

    1
    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的方法

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

    接着我添加

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

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

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

    然后改写insert方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    - (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();
        }
    }

    其实就是加入了

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

    这句.

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

    被遗忘的地方

    Sections数量,决定了有多少组

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

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

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

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    - (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通知方法.

  • 相关阅读:
    POJ2778 DNA Sequence AC自动机上dp
    codeforces732F Tourist Reform 边双联通分量
    codeforces786B Legacy 线段树优化建图
    洛谷P3588 PUS 线段树优化建图
    codeforces1301D Time to Run 模拟
    codeforces1303B National Project 二分或直接计算
    codeforces1303C Perfect Keyboard 模拟或判断欧拉路
    codeforces1303D Fill The Bag 二进制应用+贪心
    python之路——使用python操作mysql数据库
    python之路——mysql索引原理
  • 原文地址:https://www.cnblogs.com/isItOk/p/5357358.html
Copyright © 2011-2022 走看看