Можно ли заставить NSFetchedResultsController удалить объект, если одно из свойств объекта не соответствует его предикату?


У меня есть NSFetchedResultsController-backed UICollectionViewController, который заполнен списком объектов. Каждый объект имеет свойство BOOL, называемое deleted. Мой контроллер выборки использует следующий предикат для фильтрации моих объектов.

[NSPredicate predicateWithFormat:@"deleted == NO"];

Моя проблема заключается в том, что когда я удаляю объект, помечая его как deleted = @YES. Последующий метод didChangeObject: сообщает мне, что объект был обновлен и нет исключено . И объект не удаляется из представления коллекции. Если я закройте и перезагрузите моем приложении объект не отображается в представлении коллекции, что является правильным поведением.

Есть ли что-то, что я делаю неправильно, или это ожидаемое поведение NSFetchedResultsController?

Обновление по запросу вот код:

Конфигурация контроллера выборки:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"deleted == %@", @NO];
NSSortDescriptor *timestampSortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timestamp" ascending:NO];
NSSortDescriptor *prioritySortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"priority" ascending:NO];
NSManagedObjectContext *managedObjectContext = [NSManagedObjectContext MR_defaultContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:[GYNotification description] inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
[request setIncludesSubentities:YES];
[request setSortDescriptors:sortDescriptors];       
[request setPredicate:predicate];

NSFetchedResultsController *aFetchedResultsController =
    [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                           managedObjectContext:managedObjectContext
                                             sectionNameKeyPath:sectionNameKeyPath
                                                      cacheName:nil];

Тогда методы делегата контроллера выборки:

- (void)controller:(NSFetchedResultsController *)controller
   didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)indexPath
     forChangeType:(NSFetchedResultsChangeType)type
      newIndexPath:(NSIndexPath *)newIndexPath {
    NSMutableDictionary *change = [NSMutableDictionary new];
    switch(type) {
        case NSFetchedResultsChangeInsert:
            change[@(type)] = newIndexPath;
            break;
        case NSFetchedResultsChangeDelete:
            change[@(type)] = indexPath;
            break;
        case NSFetchedResultsChangeUpdate:
            change[@(type)] = indexPath;
            break;
        case NSFetchedResultsChangeMove:
            change[@(type)] = @[indexPath, newIndexPath];
            break;
    }
    [_objectChanges addObject:change];
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    if ([_objectChanges count] > 0) {
        [self.collectionView performBatchUpdates:^{
            for (NSDictionary *change in _objectChanges) {
                [change enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, id obj, BOOL *stop) {
                    NSFetchedResultsChangeType type = [key unsignedIntegerValue];
                    switch (type)
                    {
                        case NSFetchedResultsChangeInsert:
                            [self.collectionView insertItemsAtIndexPaths:@[obj]];
                            break;
                        case NSFetchedResultsChangeDelete:
                            [self.collectionView deleteItemsAtIndexPaths:@[obj]];
                            break;
                        case NSFetchedResultsChangeUpdate:
                            [self.collectionView reloadItemsAtIndexPaths:@[obj]];
                            break;
                        case NSFetchedResultsChangeMove:
                            [self.collectionView moveItemAtIndexPath:obj[0] toIndexPath:obj[1]];
                            break;
                    }
                }];
            }
        } completion:nil];
    }

    [_objectChanges removeAllObjects];
}
2 2

2 ответа:

Это поведение похоже на то, что я ожидал бы от NSFetchedResultsController. На самом деле вы просто делаете обновление для одного из ваших объектов. Тот факт, что он назван deleted, не имеет никакого значения. На самом деле, называть его deleted немного опасно, на мой взгляд, поскольку NSManagedObject уже имеет метод isDeleted.

Похоже, что вы хотите скрыть определенные управляемые объекты из поля зрения, не удаляя их на самом деле. Я бы предложил переименовать это свойство deleted в нечто вроде shouldBeVisible или markedForDeletion. Таким образом, намерение является немного яснее, и не будет такой путаницы, в каком состоянии находится ваш объект на самом деле.

Вам нужно удалить управляемые объекты следующим образом:

NSManagedObjectContext *context = ... ;
NSManagedObject *managedObjectToDelete = ... ;

[context deleteObject:managedObjectToDelete];

Только тогда ваш NSFetchedResultsController обнаружит удаление.