代码之家  ›  专栏  ›  技术社区  ›  Crystal

删除对象时为null indexPaths

  •  1
  • Crystal  · 技术社区  · 12 年前

    我搞不清楚,但当我从 NSFetchedResultsController .

    当我删除我的对象时,我会这样做:

    - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
        if (editingStyle == UITableViewCellEditingStyleDelete) {
            // Delete the object
            NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
            [context deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]];
    
            [self saveContext];
        }
    }
    

    设置 NSFetchedResults控制器 :

    - (NSFetchedResultsController *)fetchedResultsController {
        if (_fetchedResultsController != nil) {
            return _fetchedResultsController;
        }
        NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
        [fetchRequest setFetchBatchSize:20];
    
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"Route" inManagedObjectContext:self.managedObjectContext];
        [fetchRequest setEntity:entity];
    
        NSSortDescriptor *nameSort = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)];
        NSArray *sortDescriptors = @[nameSort];
        [fetchRequest setSortDescriptors:sortDescriptors];
    
        NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:@"Routes"];
        self.fetchedResultsController = aFetchedResultsController;
        self.fetchedResultsController.delegate = self;
    
        NSError *error = nil;
        if (![self.fetchedResultsController performFetch:&error]) {
            NSLog(@"Unresolved error with NSFetchedResultsController: %@", [error description]);
            abort();
        }
    
        return _fetchedResultsController;
    }
    

    这就是故障发生的地方:

    - (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
    
        switch (type) {
                // Data was inserted - insert the data into the table view
            case NSFetchedResultsChangeInsert: {
                [self.savedRoutesTableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
    
                break;
            }
                // Data was deleted - delete the data from the table view
            case NSFetchedResultsChangeDelete: {
                [self.savedRoutesTableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
                break;
            }
            case NSFetchedResultsChangeUpdate: {
                SavedRoutesTableViewCell *cell = (SavedRoutesTableViewCell *)[self.savedRoutesTableView cellForRowAtIndexPath:indexPath];
                [cell configureCellWithRoute:[controller objectAtIndexPath:newIndexPath]];
                break;
            }
            case NSFetchedResultsChangeMove: {
                [self.savedRoutesTableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
                [self.savedRoutesTableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
                break;
            }
            default:
                break;
        }
    }
    

    在didChangeObject方法中,我的indexPath和newIndexPath都为nil。我可以NSLog我的对象,并且我确实看到了实体。它在 [self.savedRoutesTableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; 方法,但出现异常:

    CoreData: error: Serious application error.  Exception was caught during Core Data change processing.  This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification.  *** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0] with userInfo (null)
    

    当我保存这个对象时,我会这样保存它:

    self.route.name = routeName;
    NSManagedObjectContext *tempContext = [self.route managedObjectContext];
    
    [tempContext performBlock:^{
            NSError *error = nil;
            if (![tempContext save:&error]) {
                NSLog(@"an error occurred: %@", [error localizedDescription]);
            }
    
            [self.managedObjectContext performBlock:^{
                NSError *error = nil;
                if (![_managedObjectContext save:&error]) {
                    NSLog(@"error in main context: %@", [error localizedDescription]);
                }
            }];
        }];
    

    由于 NSFetchedResults控制器 只是没有给我返回已删除对象的indexPath。有什么想法吗?提前谢谢。

    编辑: 我找到了导致错误的罪魁祸首,但我不确定为什么会这样。基本上,我有一个ViewController,如果它正在编辑路线,它会从主主运行中心接收一个路线实体,或者如果你正在创建一个新路线,它就会插入一个新实体。因此,在那个viewController中,如果我正在编辑一个路由,因为我试图使用两个MOC,一个temp,一个main作为它的父级,这样如果用户决定取消而不创建新的路由,我可以很容易地丢弃东西,我需要将该路由转移到另一个上下文,以使我拥有的其他代码工作。因此,“转移”看起来像:

        NSManagedObjectContext *moc = _route.managedObjectContext;
        NSManagedObjectID *routeId = [_route objectID];
        self.tempContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        self.tempContext.parentContext = moc;
        NSManagedObject *localRoute = [self.tempContext objectWithID:routeId];
        self.route = localRoute;
    

    有了这个代码,我在现有路线上添加位置是可行的,因为这些位置在相同的上下文中,但不知何故,它会把从主运行中心删除现有路线搞砸。不确定为什么以及最好的解决方案是什么。

    2 回复  |  直到 12 年前
        1
  •  0
  •   AntonijoDev    11 年前

    遇到了同样的问题,并通过确保NSFetchedResultsController始终使用相同的NSManagedContext解决了这个问题。例如,如果您从带有fetch控制器的数据库中提取对象,并且以后要删除该对象,请确保fetch控制器使用与提取过程中使用的托管上下文相同的托管上下文。

    NSFetchedResultsController针对使用UITableView进行了优化,UITableView是用户界面组件,用户界面应始终由主线程处理,因此无需每次进入fetch时都创建新的NSManagedContext。。。因此,实现此代码应该可以解决此问题:

    @synthesis fetchedResultsController=__fetchedresultsControlleor; @synthesis managedObjectContext=__managedObjectContext;

    - (NSManagedObjectContext *)managedObjectContext
    {
        if (__managedObjectContext != nil)
        {
            return __managedObjectContext;
        }
    
        NSPersistentStoreCoordinator *coordinator = ap.persistentStoreCoordinator;
        if (coordinator != nil)
        {
            __managedObjectContext = [[NSManagedObjectContext alloc] init];
            [__managedObjectContext setPersistentStoreCoordinator:coordinator];
        }
        return __managedObjectContext;
    }
    

    ap是指向AppDelegate的指针:

    ap = [[UIApplication sharedApplication] delegate];
    

    这段代码所做的是创建一个MOC实例,然后重用它。警告:这不是线程安全的,而且它不一定是(因为你应该只与主线程一起使用它),所以如果你误用了它,它将无法工作。。。

    使用它:

    - (NSFetchedResultsController *)fetchedResultsController
    {
        if (__fetchedResultsController != nil)
        {
            return __fetchedResultsController;
        }
        //create __fetchedResultsController
        // do some fetching
        return __fetchedResultsController;
    }
    

    所以,当您想要填充表时:

    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
    {
        return [[self.fetchedResultsController sections] count];
    }
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return [__fetchedResultsController.fetchedObjects count];
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        static NSString *CellIdentifier = @"Cell";
    
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
        }
    
        NSManagedObject *managedObject = [__fetchedResultsController objectAtIndexPath:indexPath];
    
        cell.textLabel.text = [managedObject valueForKey:@"smth."];
    
        return cell;
    }
    

    如果您的数据集仅更改:

    __fetchedResultsController = nil;
    [tableView reloadData]
    

    包括NSFetchedResultsControllers delegat方法在内的所有方法都可以正常工作,没有nil indexPaths等等。。。

    希望我帮助了某人。。。

        2
  •  0
  •   Crystal    11 年前
    NSManagedObjectContext *moc = _route.managedObjectContext;
    NSManagedObjectID *routeId = [_route objectID];
    self.tempContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    self.tempContext.parentContext = moc;
    NSManagedObject *localRoute = [self.tempContext objectWithID:routeId];
    self.route = localRoute;
    

    必须获取与路线关联的上下文。