【问题标题】:Sections and rows count NSFetchedResultsController部分和行数 NSFetchedResultsController
【发布时间】:2012-12-30 06:56:41
【问题描述】:

我有一个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;
}

样板代码:

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

- (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];
}

【问题讨论】:

    标签: ios xcode core-data nsfetchedresultscontroller


    【解决方案1】:

    我很久没有使用 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];
    }
    

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

    【讨论】:

    • 我已经在其他地方的代码中设置了所有这些东西。该代码有点被认为是“默认”,所以我没有费心发布它。
    • 你会惊讶地发现“默认”代码中有多少错误
    • 它是从 Apple 文档中复制和粘贴的。但我看到你真的很想看到它,所以我编辑了我的问题以显示它:)
    • 您的 NSFetchResultsControllerDelegate 方法负责从 controllerWillChangeContent: 到 controllerDidChangeContent: 的更新部分。如果您有 beginUpdates: 和 endUpdates:,则不需要从 UITableView 重新加载数据:。
    【解决方案2】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-13
      • 2014-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-12
      • 1970-01-01
      相关资源
      最近更新 更多