【问题标题】:NSFetchedResultsController returning wrong NSFetchedResultsChangeTypeNSFetchedResultsController 返回错误的 NSFetchedResultsChangeType
【发布时间】:2015-07-21 17:44:43
【问题描述】:

我正在使用viewDidLoad 中的以下获取请求创建一个NSFetchedResultsController

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]重新加载viewWillAppear

一个简化的Person

@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 并将其转换为NSManagedObjects。排序看起来不错。

1 Person A time 1437498898
2 Person B time 1437498897
3 Person C time 1437498896

当我使用-viewed 方法调整Person C 上的sortDate 属性时,在<NSFetchedResultsControllerDelegate> 中,我得到NSFetchedResultsChangeMove 的更改类型,并且列表的排序如下:

1 Person C time 1437498900
2 Person A time 1437498898
3 Person B time 1437498897

当我尝试对Person B 执行相同操作时,我得到了NSFetchedResultsChangeUpdate 的更改类型,并且列表的排序如下:

1 Person C time 1437498900
2 Person A time 1437498898
3 Person B time 1437498905

我可以不断更新 sortDate 的人员 AC,他们将继续正确排序。 Person B 的任何更改直到应用程序重新启动后才会显示,但随后 Person B 停止更新。删除并重新安装我的应用程序(以清除 CoreData)没有帮助。

如果我在- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath 中放置print 命令,那么我可以看到Person BsortDate 确实已更新为新值,这应该导致 NSFRC创建 Move 事件而不是 Update 更改类型。

// 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

【问题讨论】:

    标签: objective-c core-data nsfetchedresultscontroller


    【解决方案1】:

    来自NSFetchedResultsControllerDelegate的文档:

    当对象的更改属性是获取请求中使用的排序描述符之一时,将报告移动。

    在这种情况下假定更新了对象,但不会向委托发送单独的更新消息。

    当对象的状态发生变化时报告更新,但更改的属性不是排序键的一部分。

    我希望这能说明为什么您会在回调中获得不同的更改类型。考虑到这一点,我建议清理您的获取结果控制器并委托回调:

    • 消除 FRC 中的冗余谓词
    • 使用与属性名称对应的排序键:"sortDate"
    • 确保委托回调方法将表格视图单元格移动到新的索引路径,即酌情调用deleteRowsAtIndexPathsinsertRowsAtIndexPaths

    最后的想法:您为一个特定对象描述的不稳定行为(而其他对象似乎按预期工作)指向其他可能的错误,例如与更新 sortDate 属性有关。

    另外,您没有在获取的结果控制器中解释 keypath 变量。也许分组有助于您观察到的行为。

    最后,您可能是here 中描述的获取结果控制器委托的罕见故障的受害者(包括解决方法)。 - 另外,不要忘记,如果您不需要动画更改,您可以随时使 FRC 无效并调用 reloadData

    如果没有任何帮助,我会用NSDate 重构而不是NSNumber,后者更直观。

    【讨论】:

    • 委托回调没有收到带有 newIndexPathMove 更改类型 - 它收到了 Update 更改类型
    • 文档引用中的最后一句话指出了排序问题。 - 更新对象时查找错误。
    • 他们都调用相同的viewed 方法来执行此操作。为什么sortDate 会成为某些对象的排序键,而不是其他对象?
    • 我更新了答案。也许您是罕见故障的受害者。
    • 我删除了didChangeObject方法并在controllerDidChangeContent:中执行了[tableView reloadData],排序问题仍然存在。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多