节和行计数NSFetchedResultsController

时间:2013-01-16 01:53:51

标签: ios xcode core-data nsfetchedresultscontroller

我有一个NSFetchedResultsController,我已确认无论何时用户创建新对象,都会将数据保存到其中。但是,我发现唯一不更新的是NSFetchedResultsController的节和行数。我不确定为什么会这样。

我尝试过多种方式来改变新对象的创建方式。我也尝试记录过程的每一步,试着看看发生了什么,但是我真的没有太多可以记录这样的东西,所以我现在几乎没有关于为什么会发生这种情况的信息。无论如何,这是代码:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    NSLog(@"number of sections: %d", [[self.fetchedResultsController sections] count]);
    return [[self.fetchedResultsController sections] count];
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSLog(@"number of rows: %d", [[[self.fetchedResultsController sections] objectAtIndex:section] numberOfObjects]);
    return [[[self.fetchedResultsController sections] objectAtIndex:section] numberOfObjects];
}

- (void)saveForName:(NSString *)name
              photo:(NSData *)photo
         timePosted:(NSDate *)timePosted
            details:(NSString *)details
        dateAndTime:(NSDate *)dateTime
           location:(NSString *)location
{

    if (!self.shindysDatabase) {
        NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
        self.shindysDatabase = [[UIManagedDocument alloc] initWithFileURL:url];
        NSLog(@"shindy database reset.");
    }

    Shindy *shindy = (Shindy *)[NSEntityDescription insertNewObjectForEntityForName:@"Shindy" inManagedObjectContext:self.shindysDatabase.managedObjectContext];

    shindy.name = name;
    shindy.photo = photo;
    shindy.timePosted = timePosted;
    shindy.details = details;
    shindy.dateAndTime = dateTime;
    shindy.location = location;

    NSError *error = nil;
    [self.shindysDatabase.managedObjectContext save:&error];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];

    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
    }

    Shindy *shindy = (Shindy *)[NSEntityDescription entityForName:@"Shindy" inManagedObjectContext:self.shindysDatabase.managedObjectContext];
    shindy = [self.fetchedResultsController objectAtIndexPath:indexPath];

    UIImageView *avatar = [[UIImageView alloc] initWithFrame:CGRectMake(20, 10, 64, 56)];
    // Converting NSData to UIImage
    avatar.image = shindy.photo;
    avatar.clipsToBounds = NO;
    [cell addSubview:avatar];

    NSLog(@"avatar: %@", avatar);

    // The name of the user who posted the shindy
    UILabel *avatarName = [[UILabel alloc] initWithFrame:CGRectMake(90, 10, 125, 19)];
    avatarName.font = [UIFont boldSystemFontOfSize:15];
    avatarName.backgroundColor= [UIColor clearColor];
    avatarName.text = shindy.name;
    [cell addSubview:avatarName];

    NSLog(@"avatarName: %@", avatarName);

    // The time the shindy was posted
    NSDateFormatter *timePostedFormatter = [[NSDateFormatter alloc] init];
    [timePostedFormatter setDateFormat:@"mm"];
    UILabel *timePosted = [[UILabel alloc] initWithFrame:CGRectMake(280, 10, 30, 20)];
    timePosted.font = [UIFont systemFontOfSize:12];
    timePosted.textColor = [UIColor lightGrayColor];
    timePosted.backgroundColor= [UIColor clearColor];
    timePosted.text = [timePostedFormatter stringFromDate:shindy.timePosted];
    [cell addSubview:timePosted];

    NSLog(@"Time posted: %@", timePosted);

    // Formatting fetched NSDate into string
    NSDateFormatter *dateAndTimeFormatter = [[NSDateFormatter alloc] init];
    [timePostedFormatter setDateFormat:@"MM/DD/YYYY hh:mm"];
    UILabel *dateAndTimeLabel = [[UILabel alloc] initWithFrame:CGRectMake(250, 70, 30, 20)];
    dateAndTimeLabel.font = [UIFont systemFontOfSize:12];
    dateAndTimeLabel.backgroundColor= [UIColor clearColor];
    dateAndTimeLabel.text = [dateAndTimeFormatter stringFromDate:shindy.dateAndTime];
    [cell addSubview:dateAndTimeLabel];

    NSLog(@"date and time: %@", dateAndTimeLabel.text);

    // Details of the Shindy
    UILabel *shindyDescription = [[UILabel alloc] initWithFrame:CGRectMake(90, 20, 220 , 50)];
    shindyDescription.numberOfLines = 3;
    shindyDescription.font = [UIFont systemFontOfSize:12];
    shindyDescription.backgroundColor = [UIColor clearColor];
    shindyDescription.text = shindy.details;
    [cell addSubview:shindyDescription];

    NSLog(@"details: %@", shindyDescription.text);

    return cell;
}

BoilerPlate代码:

这只是在更改对象时我必须进行更新的代码。

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
    // The fetch controller is about to start sending change notifications, so prepare the table view for updates.
    [self.tableView beginUpdates];
}


- (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)controller:(NSFetchedResultsController *)controller didChangeSection:(id )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)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    // The fetch controller has sent all current change notifications, so tell the table view to process all updates.
    [self.tableView endUpdates];
}

2 个答案:

答案 0 :(得分:0)

我很长时间没有使用NSFetchedResultController,但乍一看我会说:
Where are you asking your table view to update itself?
我认为结果控制器不会触发表更新本身。


我刚才在NSFetchedResultsController文档中,我也看到了这个:

  

此外,获取的结果控制器提供以下功能:
  (可选)监视关联的受管对象中对象的更改   上下文,并将结果集中的更改报告给其委托(请参阅   “财务主任代表”)。

还有NSFetchedResultsControllerDelegate文档

  

你可以实现controllerDidChangeContent :(发送到   处理所有挂起的更改时的委托)重新加载   表格视图。


仅用于调试目的,您是否尝试删除:

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller 
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id )sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type

只是这样做:

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView reloadData];
}

我不是说这是一个解决方案,但看看结果是否相同会很有趣。

答案 1 :(得分:0)

在创建NSFetchedResultsController对象时是否指定了sectionNameKeyPath?如果您使用nil,则只会创建一个部分。

  

(instancetype)initWithFetchRequest:(NSFetchRequest *)fetchRequest managedObjectContext:(NSManagedObjectContext *)context sectionNameKeyPath:(NSString *)sectionNameKeyPath cacheName:(NSString *)name;

     

sectionNameKeyPath:   返回节名称的结果对象的关键路径。传递nil以指示控制器应生成单个部分。