Objective c NSFetchedResultsController返回错误的NSFetchedResultsChangeType
我正在创建一个Objective c NSFetchedResultsController返回错误的NSFetchedResultsChangeType,objective-c,core-data,nsfetchedresultscontroller,Objective C,Core Data,Nsfetchedresultscontroller,我正在创建一个NSFetchedResultsController,在viewDidLoad NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:NSStringFromClass([Person class])]; fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:NSStringFromSelector
NSFetchedResultsController
,在viewDidLoad
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:NSStringFromClass([Person class])];
fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:NSStringFromSelector(@selector(sortDate))
ascending:NO]];
NSFetchedResultsController *controller = [[NSFetchedResultsController alloc] initWithFetchRequest:request
managedObjectContext:self.mainManagedObjectContext
sectionNameKeyPath:nil
cacheName:nil];
controller.delegate = delegate;
NSError *error;
if (![controller performFetch:&error]) {
NSLogError(error);
}
// Connecting up all the delegates for UITableView
然后在视图中重新加载它将与[self.tableView reloadData]
简化的人
@interface Person : NSManagedObject
/// an NSTimeInterval representing the Unix Epoch
@property (nonatomic, retain) NSNumber *sortDate;
- (void)viewed;
@end
@implementation Person
// nothing fancy or custom - no extra KVO or primitive assignments
@dynamic sortDate;
- (void)viewed {
self.sortDate = @([NSDate date].timeIntervalSince1970);
}
@end
我的数据是通过网络请求生成的,以获取一组json并将其转换为NSManagedObject
s。排序看起来不错
1 Person A time 1437498898
2 Person B time 1437498897
3 Person C time 1437498896
当我使用-viewd
方法调整Person C
上的sortDate
属性时,在
中,我得到一个更改类型NSFetchedResultsChangeMove
,列表排序如下:
1 Person C time 1437498900
2 Person A time 1437498898
3 Person B time 1437498897
1 Person C time 1437498900
2 Person A time 1437498898
3 Person B time 1437498905
当我尝试对人员B
执行相同操作时,我得到的更改类型是NSFetchedResultsChangeUpdate
,列表排序如下:
1 Person C time 1437498900
2 Person A time 1437498898
3 Person B time 1437498897
1 Person C time 1437498900
2 Person A time 1437498898
3 Person B time 1437498905
我可以持续更新个人A
和C
的sortDate
,他们将继续正确排序。对Person B
的任何更改只有在应用程序重新启动后才会显示,但Person B
停止更新。删除并重新安装我的应用程序(以清除CoreData)没有帮助
如果我将print
命令放在-(void)控制器:(nsfetchedresultscoontroller*)控制器didChangeObject:(id)一个对象atIndexPath:(nsindepath*)indexath for changeType:(NSFetchedResultsChangeType)type newindexath:(nsindepath*))newIndexPath
然后我可以看到人员B
的sortDate
确实已更新为新值,这将导致NSFRC创建移动
事件,而不是更新
更改类型
// Original Sort (logs from cellForRowAtIndexPath)
Time 1437506506 - Person B
Time 1437506490 - Person C
Time 1437506381 - Person D
Time 1437506128 - Person A
// Change Person A
Updating SortDate 1437506128 --> 1437506599
Time 1437506599 - Person A for NSFetchedResultsChangeMove
// Sorted Correctly
Time 1437506599 - Person A
Time 1437506506 - Person B
Time 1437506490 - Person C
Time 1437506381 - Person D
// Change Person B
Updating SortDate 1437506506 --> 1437506610
Time 1437506610 - Person B for NSFetchedResultsChangeUpdate
// Sorted Incorrectly
Time 1437506599 - Person A
Time 1437506610 - Person B
Time 1437506490 - Person C
Time 1437506381 - Person D
那么,为什么NSFetchedResultsController
返回了错误的NSFetchedResultsChangeType
?来自NSFetchedResultsController委托的文档:
当对象上已更改的属性是fetch请求中使用的排序描述符之一时,将报告移动
在这种情况下,假定对象更新,但不向委托发送单独的更新消息
当对象的状态发生更改时,会报告更新,但更改的属性不是排序键的一部分
我希望这能清楚地解释为什么您在回调中得到不同的更改类型。考虑到这一点,我建议清理获取的结果控制器和委托回调:
- 消除FRC中的冗余谓词
- 使用与属性名称相对应的排序键:
“sortDate”
- 确保委托回调方法将表视图单元格移动到新的索引路径,即根据需要调用
deleteRowsAtIndexPaths
和insertRowsAtIndexPaths
最后一点思考:您为一个特定对象描述的不稳定行为(而其他对象似乎按预期工作)指向了其他可能的错误,例如与更新sortDate
属性有关的错误
此外,您没有解释“获取结果”控制器中的keypath
变量。也许分组对您观察到的行为有影响
最后,您可能是所描述的获取结果控制器委托(包括解决方法)的罕见故障的受害者另外,不要忘记,如果您不需要设置更改的动画,您总是可以使FRC无效并调用reloadData
如果没有任何帮助,我将使用NSDate
而不是NSNumber
进行重构,这更直观。代理回调不会收到带有newindepath
的移动
更改类型-它会收到更新
更改类型文档引用中的最后一句话指向排序问题。-更新对象时查找错误。它们都调用相同的viewsed
方法来执行此操作。为什么sortDate
会是某些对象的排序键,而不是其他对象的排序键?我更新了答案。可能您是一个罕见故障的受害者。我删除了didChangeObject
方法,并在controllerDidChangeContent:
中执行了[tableView reloadData]
,排序问题保持不变。