• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

ios核心数据: make sure object is deleted from data source

[复制链接]
菜鸟教程小白 发表于 2022-12-11 19:19:10 | 显示全部楼层 |阅读模式 打印 上一主题 下一主题

更新:在评论中有人指出我不必要地分派(dispatch)到主线程。在删除调度和不必要的 begin/end updates 之后,现在当我尝试删除一个单元格时,它会调用 didChangeObject 与 case NSFetchedResultsChangeUpdate (相反到 NSFetchedResultsChangeDelete),它调用 configureCell

使程序崩溃的行是 CollectedLeaf* theCollectedLeaf = [collectionFetchedResultsController objectAtIndexPath:indexPath]; 在下面的方法中。崩溃日志是,节列表中索引 20 处没有节

- (void)configureCellSpeciesCell *)cell atIndexPathNSIndexPath *)indexPath
{
    CollectedLeaf* theCollectedLeaf = [collectionFetchedResultsController objectAtIndexPath:indexPath];
    [cell setCollectedLeaf:theCollectedLeaf];
}

每次滑动以从表格中删除单元格时,我都会收到 Invalid update: invalid number of rows in section 错误。我在 controllerDidChangeContent[_table endUpdates] 处获得断点。

在许多 SO 帖子中,出现此错误的原因是在从表中删除行之前尚未从数据源中删除对象。我从 commitEditingStyle 中的数据源中删除对象,该对象在 didChangeObject 中的 deleteRowsAtIndexPaths 之前调用。

尽管我下了订单,但我仍然收到 Invalid update 的事实让我认为我没有正确/成功地从数据源中删除它。我还是 iOS 新手 - 如何确保从我的核心数据中删除对象?

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

- (void)controllerNSFetchedResultsController *)controller didChangeObjectid)anObject
       atIndexPathNSIndexPath *)indexPath forChangeTypeNSFetchedResultsChangeType)type
      newIndexPathNSIndexPath *)newIndexPath {
    switch(type) {

        case NSFetchedResultsChangeInsert:
            [_table beginUpdates];

            [_table insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                          withRowAnimation:UITableViewRowAnimationFade];
            [_table endUpdates];
            break;

        case NSFetchedResultsChangeDelete:
            NSLog(@"delete called");
            [_table deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                          withRowAnimation:UITableViewRowAnimationFade];


            break;

        case NSFetchedResultsChangeUpdate:
           // [self configureCell:[_table cellForRowAtIndexPath:indexPath]
                   // atIndexPath:indexPath];
            [_table reloadRowsAtIndexPaths[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
            NSLog(@"fetched update");
            break;

        case NSFetchedResultsChangeMove:
            [_table deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                          withRowAnimation:UITableViewRowAnimationFade];
            [_table insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                          withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

- (void)controllerNSFetchedResultsController *)controller didChangeSectionid <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
    switch(type)
    {
        case NSFetchedResultsChangeInsert:
            [_table insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [_table deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
            break;
        case NSFetchedResultsChangeMove:
            break;
        case NSFetchedResultsChangeUpdate:
            break;
    }
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
    [_table endUpdates];
}
-(UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if(_segmentedControl.selectedSegmentIndex == 1) {
        NSLog(@"index path at editingStyleForRowAtIndexPath %@", indexPath);
        return UITableViewCellEditingStyleDelete;
    }
    return NULL;
}

- (void)tableView:(UITableView*)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath
{
    // [super tableView: tableView didEndEditingRowAtIndexPath:indexPath];
    if(_segmentedControl.selectedSegmentIndex == 1) {
        for (UITableViewCell *cell in [_table visibleCells]) {
            for (UIView *subview in cell.contentView.subviews)
                [subview.layer removeAllAnimations];
        }
    }
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    /*Only allow deletion for collection table */
    if(_segmentedControl.selectedSegmentIndex == 1) {
        if (editingStyle == UITableViewCellEditingStyleDelete)
        {
            NSLog(@"index path at commitediting style %@", indexPath);
            CollectedLeaf* collectedLeaf = [collectionFetchedResultsController objectAtIndexPath:indexPath];
            LeafletPhotoUploader * leafletPhotoUploader = [[LeafletPhotoUploader alloc] init];
            leafletPhotoUploader.collectedLeaf = collectedLeaf;

            if([LeafletUserRegistration isUserRegistered]) {
                [leafletPhotoUploader deleteCollectedLeaf:collectedLeaf delegate:self];
            }

            // Delete the managed object for the given index path
            NSManagedObjectContext *context = [collectionFetchedResultsController managedObjectContext]; 
                [context deleteObject:[collectionFetchedResultsController objectAtIndexPath:indexPath]];

            // Save the context.
            NSError *error;
            if (![context save:&error])
            {
                NSLog(@"Failed to save to data store: %@", [error localizedDescription]);
                NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
                if(detailedErrors != nil && [detailedErrors count] > 0)
                {
                    for(NSError* detailedError in detailedErrors)
                    {
                        NSLog(@"  DetailedError: %@", [detailedError userInfo]);
                    }
                }
                else
                {
                    NSLog(@"  %@", [error userInfo]);
                }
            }
        }
    }
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"speciesCell";

    SpeciesCell* speciesCell = (SpeciesCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    [self configureCell:speciesCell atIndexPath:indexPath];
    speciesCell.labelCheckMark.backgroundColor = [UIColor blackColor];

    return speciesCell;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {

    return 1;
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{

    id <NSFetchedResultsSectionInfo> sectionInfo = [[collectionFetchedResultsController sections] objectAtIndex:section];
    if([sectionInfo numberOfObjects] == 0){
        UILabel *noDataLabel         = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, tableView.bounds.size.height)];
        noDataLabel.text             = @"ress the Snap It! tab to start collecting!";
        //Start your collection by tapping on the Snap It! tab.";
        noDataLabel.textColor        = [UIColor whiteColor];
        noDataLabel.textAlignment    = NSTextAlignmentCenter;
        tableView.backgroundView = noDataLabel;
        tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    }
    return [sectionInfo numberOfObjects];
}



Best Answer-推荐答案


This post saved me

objectAtIndexPath 有很多错误,只能在边界检查中调用,所以我现在使用嵌套 if 语句中的核心数据对象完成所有工作

    CollectedLeaf* theCollectedLeaf = nil;
    if ([[collectionFetchedResultsController sections] count] > [indexPath section]){
        id <NSFetchedResultsSectionInfo> sectionInfo = [[collectionFetchedResultsController sections] objectAtIndex:[indexPath section]];
        if ([sectionInfo numberOfObjects] > [indexPath row]){
            theCollectedLeaf = [collectionFetchedResultsController objectAtIndexPath:indexPath];

        //do whatever else I need, delete the object, etc
        }

    }

正如链接帖子所述,

"The reason you are getting an exception is that the state of the NSFetchedResultsController is getting out of sync with the state of the tableview. When your crash happens the tableView just asked your delegate methods (numberOfSectionsInTableView and tableView:numberOfRowsInSection: for the number of rows and sections. When it asked that, the NSFetchedResultsController had data in it, and gave positive values (1 section, 3 rows). But in-between that happening and your crash, the entities represented by the NSFetchedResultsController were deleted from the NSManagedObjectContext. Now cellForRowAtIndexPath: is being called with an outdated indexPath parameter."

关于ios核心数据: make sure object is deleted from data source,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47340419/

回复

使用道具 举报

懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关注0

粉丝2

帖子830918

发布主题
阅读排行 更多
广告位

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap