带有谓词的 NSFetchedResultsController 在更新后获取 NSFetchedResultsChangeDelete
NSFetchedResultsController with predicate gets NSFetchedResultsChangeDelete after update
NSFetchedResultsController
有一个谓词,存在一些严重的问题。更新联系人 属性 的值后会出现此问题。这就是它的配置方式:
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Contacts" inManagedObjectContext:_addressbookMainObjectContext
NSSortDescriptor *sortNameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"lastnameFirstLetter" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)];
NSSortDescriptor *sortNameDescriptor1 = [[NSSortDescriptor alloc] initWithKey:@"firstName" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortNameDescriptor, sortNameDescriptor1, nil];
NSFetchRequest *fetchRequest = [NSFetchRequest new];
[fetchRequest setEntity:entityDescription];
[fetchRequest setSortDescriptors:sortDescriptors];
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"contactType == 3"];;
NSFetchedResultsController *fetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:_addressbookMainObjectContext
sectionNameKeyPath:@"sectiononIdentifier"
cacheName:nil];
_fetchResultController = fetchedResultsController;
_fetchResultController.delegate = self;
谓词设置为获取筛选的行。
这是父子上下文的配置方式:
_addressbookMainObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
_addressbookMainObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
_addressbookMainObjectContext setParentContext:_writerContext];
_writerContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_writerContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
[_writerContext setPersistentStoreCoordinator:_persistentStoreCoordinator];
为了更新行,使用另一个私有上下文来完成这项工作:
NSManagedObjectContext *ctx = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[ctx setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
[ctx setParentContext:[PalDataCache sharedInstance].addressbookMainObjectContext];
[ctx performBlockAndWait:^{
NSError *errorAllCons = nil;
NSArray *allCons = [context executeFetchRequest:allContacts error:&errorAllCons];
Contacts * contact = [allCons objectAtIndex:0];
contact.pictureUpdatedForRedownload = [NSNumber numberWithBool:YES];
}];
因此在此临时上下文中保存更改后。 NSFetchedResultsControllerDelegate
被触发:
- (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:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
break;
case NSFetchedResultsChangeDelete:
{
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
break;
}
case NSFetchedResultsChangeUpdate:
[self configureCell:(contactCell*)[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
break;
}
}
这会触发 NSFetchedResultsChangeDelete
,导致该行从 table 中删除,但不会从数据库中删除。重新获取后,一切都回到了那里。这是非常糟糕的用户体验。谓词是根据用户定义的过滤器设置的。如果提取请求中没有谓词,则不会发生此问题。我究竟做错了什么?是否有针对此行为的解决方法?
编辑:
当我尝试更新联系人主要上下文中的记录时,仍然会出现此问题。所以它是主要上下文和写入上下文组合。
我遇到了同样的问题。我就是这样修复的:
- 我的谓词使用了类似 ("index == %@")
- 我正在过滤一个整数值,但我传递的是@"1"。
- 将其更改为 %i 并传递整数,成功了。
NSFetchedResultsController
有一个谓词,存在一些严重的问题。更新联系人 属性 的值后会出现此问题。这就是它的配置方式:
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Contacts" inManagedObjectContext:_addressbookMainObjectContext
NSSortDescriptor *sortNameDescriptor = [[NSSortDescriptor alloc] initWithKey:@"lastnameFirstLetter" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)];
NSSortDescriptor *sortNameDescriptor1 = [[NSSortDescriptor alloc] initWithKey:@"firstName" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortNameDescriptor, sortNameDescriptor1, nil];
NSFetchRequest *fetchRequest = [NSFetchRequest new];
[fetchRequest setEntity:entityDescription];
[fetchRequest setSortDescriptors:sortDescriptors];
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"contactType == 3"];;
NSFetchedResultsController *fetchedResultsController =
[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest
managedObjectContext:_addressbookMainObjectContext
sectionNameKeyPath:@"sectiononIdentifier"
cacheName:nil];
_fetchResultController = fetchedResultsController;
_fetchResultController.delegate = self;
谓词设置为获取筛选的行。
这是父子上下文的配置方式:
_addressbookMainObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
_addressbookMainObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
_addressbookMainObjectContext setParentContext:_writerContext];
_writerContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_writerContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
[_writerContext setPersistentStoreCoordinator:_persistentStoreCoordinator];
为了更新行,使用另一个私有上下文来完成这项工作:
NSManagedObjectContext *ctx = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[ctx setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
[ctx setParentContext:[PalDataCache sharedInstance].addressbookMainObjectContext];
[ctx performBlockAndWait:^{
NSError *errorAllCons = nil;
NSArray *allCons = [context executeFetchRequest:allContacts error:&errorAllCons];
Contacts * contact = [allCons objectAtIndex:0];
contact.pictureUpdatedForRedownload = [NSNumber numberWithBool:YES];
}];
因此在此临时上下文中保存更改后。 NSFetchedResultsControllerDelegate
被触发:
- (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:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
break;
case NSFetchedResultsChangeDelete:
{
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
break;
}
case NSFetchedResultsChangeUpdate:
[self configureCell:(contactCell*)[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
break;
}
}
这会触发 NSFetchedResultsChangeDelete
,导致该行从 table 中删除,但不会从数据库中删除。重新获取后,一切都回到了那里。这是非常糟糕的用户体验。谓词是根据用户定义的过滤器设置的。如果提取请求中没有谓词,则不会发生此问题。我究竟做错了什么?是否有针对此行为的解决方法?
编辑: 当我尝试更新联系人主要上下文中的记录时,仍然会出现此问题。所以它是主要上下文和写入上下文组合。
我遇到了同样的问题。我就是这样修复的:
- 我的谓词使用了类似 ("index == %@")
- 我正在过滤一个整数值,但我传递的是@"1"。
- 将其更改为 %i 并传递整数,成功了。