Objective c NSFetchedResultsController在保存列出的一个对象后损坏了排序
我有一组用于CoreData浏览的通用视图/类,但在保存对所列对象之一的属性的更改后,我的“获取结果”控制器的排序顺序出现问题 在Objective c NSFetchedResultsController在保存列出的一个对象后损坏了排序,objective-c,ios,nsfetchedresultscontroller,Objective C,Ios,Nsfetchedresultscontroller,我有一组用于CoreData浏览的通用视图/类,但在保存对所列对象之一的属性的更改后,我的“获取结果”控制器的排序顺序出现问题 在视图中将出现:我的表视图控制器中,我设置了“获取结果”控制器,如下所示: - (void) setupFetchedResultsController { NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName: self.entityToList]; request.p
视图中将出现:
我的表视图控制器中,我设置了“获取结果”控制器,如下所示:
- (void) setupFetchedResultsController {
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName: self.entityToList];
request.predicate = self.entitySelectionPredicate; // Typically nil
request.sortDescriptors = self.entitySortDescriptorList;
self.fetchedResultsController = [[NSFetchedResultsController alloc]
initWithFetchRequest: request
managedObjectContext: self.contextForEntity
sectionNameKeyPath: self.keyPathForSections
cacheName: nil]; /* Not chacheing */
}
在didselectRowatingIndexPath
中,我将此tableview控制器推送到一个细节表格视图控制器,如下所示:
- (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath {
id objectInCell = [self.fetchedResultsController objectAtIndexPath: indexPath];
ManagedObjectDetailTableViewController *dvc = [[ManagedObjectDetailTableViewController alloc]
initWithStyle: UITableViewStyleGrouped];
dvc.detailItem = objectInCell;
[self.navigationController pushViewController: dvc animated: YES];
}
ManagedObjectDetailTableViewController为每个属性和每个关系都有一行。在didselectRowatinedexpath
中,如果选择了包含and属性的行,我将推送到ManagedObjectAttributeEditViewController视图控制器:
- (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath {
// Section 0 has the attributes for the 'detailItem' object alphabetically by name
if( indexPath.section == 0 ) {
ManagedObjectAttributeEditViewController *evc = [[ManagedObjectAttributeEditViewController alloc]
initWithNibName: @"ManagedObjectAttributeEditViewController" bundle: nil];
evc.editedObject = self.detailItem;
evc.delegate = self;
// Figure out from the row which attribute was selected
NSEntityDescription *entity = self.detailItem.entity;
NSDictionary *attributes = entity.attributesByName;
NSArray *keys = [attributes allKeys];
keys = [keys sortedArrayUsingSelector: @selector(compare:)];
NSString *key = [keys objectAtIndex: indexPath.row];
evc.editedFieldKey = key;
[self.navigationController pushViewController: evc animated: YES];
// The other sections are the relationships for the 'detailItem' object
} else {
// Code omitted as not relevant for the error.
}
}
ManagedObjectAttributeEditViewController具有文本字段等,以允许编辑属性值。触摸其“保存”按钮时,将执行:
- (IBAction) save {
id valueFromView;
NSAttributeType type = [self typeForEditedAttribute];
switch( type ) {
case NSDateAttributeType:
valueFromView = self.datePicker.date;
break;
case NSStringAttributeType:
if( [self.fieldKeyTester shouldUseTextViewForKey: self.editedFieldKey inEntity: self.editedObject.entity.name] ) {
valueFromView = self.textView.text;
} else {
valueFromView = self.textField.text;
}
break;
case NSInteger16AttributeType:
case NSInteger32AttributeType:
case NSInteger64AttributeType:
valueFromView = [NSNumber numberWithInteger: [self.textField.text integerValue]];
break;
case NSDecimalAttributeType:
case NSDoubleAttributeType:
case NSFloatAttributeType:
valueFromView = [NSNumber numberWithDouble: [self.textField.text doubleValue]];
break;
case NSBooleanAttributeType:
valueFromView = [NSNumber numberWithBool: self.switchControl.isOn];
break;
case NSObjectIDAttributeType:
case NSTransformableAttributeType:
case NSBinaryDataAttributeType:
case NSUndefinedAttributeType:
NSLog( @"Don't know how to handle attribute type: %d in %s", type, __func__ );
break;
default:
NSLog( @"Unrecognized attribute type: %d in %s", type, __func__ );
break;
}
[self.delegate managedObjectAttributeEditViewController: self
didSaveValue: valueFromView forKey: self.editedFieldKey];
}
ManagedObjectDetailTableViewController设置为委托,而didSaveValue:forKey:
方法为:
- (void) managedObjectAttributeEditViewController: (ManagedObjectAttributeEditViewController *) controller didSaveValue: (id) value forKey: (NSString *) key {
if( value && key ) {
[self.detailItem setValue: value forKey: key];
NSError *error;
if( ![self.detailItem.managedObjectContext save: &error] ) {
// Update to handle the error appropriately.
NSLog( @"Unresolved error doing save of attribute %@.\n%@", key, error.localizedDescription );
} else {
NSLog( @"-- successfully saved" );
}
} else {
NSLog( @"Got a cancel from edit attribute" );
}
// OK, the attribute editing view controller has told us it is done, pop it
[self.navigationController popViewControllerAnimated: YES];
}
- (void) managedObjectAttributeEditViewController: (ManagedObjectAttributeEditViewController *) controller
didSaveValue: (id) value forKey: (NSString *) key {
if( value && key ) {
[self.detailItem setValue: value forKey: key];
NSError *error;
if( ![self.detailItem.managedObjectContext save: &error] ) {
// Update to handle the error appropriately.
NSLog( @"Unresolved error doing save of attribute %@.\n%@", key, error.localizedDescription );
} else {
NSLog( @"-- successfully saved" );
if( [self.detailItem.managedObjectContext.parentContext.hasChanges] ) {
if( ![self.detailItem.managedObjectContext.parentContext save: &error] ) {
NSLog( @"Unresolved error doing save of parent context for attribute %@.\n%@", key, error.localizedDescription );
} else {
NSLog( @"-- successfully saved the parent context too!" );
}
}
}
} else {
NSLog( @"Got a cancel from edit attribute" );
}
// OK, the attribute editing view controller has told us it is done, pop it
[self.navigationController popViewControllerAnimated: YES];
}
因此,如果我从实体的对象列表开始,并且它们被正确排序。我触摸一行并将其推送到ManagedObjectDetailTableViewController。我触摸其中的属性行,它将推送到ManagedObjectAttributeEditViewController。我更改值并触摸保存。这会弹出到ManagedObjectDetailTableViewController,在那里一切看起来都很好。然后,我点击后退按钮返回实体的对象列表,但现在它们不再排序(它们似乎总是以相同的顺序排列,但我无法识别顺序的模式)
如果在执行保存操作后,在触摸“后退”按钮之前计数到10,则列表将正确排序
如果在didSaveValue:forKey:
中注释掉[self.detailItem.managedObjectContext save:&error]
方法调用,则实体的对象列表仍保持正确排序,但如果在自动保存之前退出应用程序,则会丢失更改
这使我认为这与[self.detailItem.managedObjectContext save:&error]
未完成以及获取的结果控制器(使用相同的NSManagedObjectContext)由于某种原因无法检索已排序的数据有关
我正在更改其值的属性不包含在排序描述符中,因此在修改值之前和之后显示的顺序应该相同。我的数据库相当大,可能需要几秒钟才能将其写入磁盘。我在模拟器和设备上看到了iOS 5.1的问题
有没有人经历过类似的事情或有什么建议
对不起,这是这么长的风和快乐的7月4日为所有这些Stackoverflowers在美国
修订的ManagedObjectDetailTableViewController委托方法
didSaveValue:forKey:
方法是:
- (void) managedObjectAttributeEditViewController: (ManagedObjectAttributeEditViewController *) controller didSaveValue: (id) value forKey: (NSString *) key {
if( value && key ) {
[self.detailItem setValue: value forKey: key];
NSError *error;
if( ![self.detailItem.managedObjectContext save: &error] ) {
// Update to handle the error appropriately.
NSLog( @"Unresolved error doing save of attribute %@.\n%@", key, error.localizedDescription );
} else {
NSLog( @"-- successfully saved" );
}
} else {
NSLog( @"Got a cancel from edit attribute" );
}
// OK, the attribute editing view controller has told us it is done, pop it
[self.navigationController popViewControllerAnimated: YES];
}
- (void) managedObjectAttributeEditViewController: (ManagedObjectAttributeEditViewController *) controller
didSaveValue: (id) value forKey: (NSString *) key {
if( value && key ) {
[self.detailItem setValue: value forKey: key];
NSError *error;
if( ![self.detailItem.managedObjectContext save: &error] ) {
// Update to handle the error appropriately.
NSLog( @"Unresolved error doing save of attribute %@.\n%@", key, error.localizedDescription );
} else {
NSLog( @"-- successfully saved" );
if( [self.detailItem.managedObjectContext.parentContext.hasChanges] ) {
if( ![self.detailItem.managedObjectContext.parentContext save: &error] ) {
NSLog( @"Unresolved error doing save of parent context for attribute %@.\n%@", key, error.localizedDescription );
} else {
NSLog( @"-- successfully saved the parent context too!" );
}
}
}
} else {
NSLog( @"Got a cancel from edit attribute" );
}
// OK, the attribute editing view controller has told us it is done, pop it
[self.navigationController popViewControllerAnimated: YES];
}
我现在了解到,这种双重保存对于使用最新iOS进行永久存储的更改是必要的,因为对于父上下文,保存只会上升一个级别。我不明白为什么不将save传播到永久存储会扰乱排序顺序。也许在我的代码中有其他一些bug,这是屏蔽的,或者可能只是它的工作方式…好的,根据您的编辑,包括新的堆栈跟踪: 您正在使用UIManagedDocument来管理核心数据堆栈。这意味着第一次保存可能来自UIDocument的主线程上下文,第二次保存可能来自其后台上下文。能否确认您正在使用UIManagedDocument的managedObjectContext上下文中的对象(与您自己创建的其他上下文相反) 还有一件事。您能否确认
setupFetchedResultsController
方法中的entitySortDescriptorList
不会以某种方式变为零
最后,与其他诊断一样:
- 尝试从顶级视图控制器调用
,看看会发生什么save:
- 如果为NSFetchedResultsController进行委托,会发生什么情况?你收到变更通知了吗?它们看起来合理吗
获取的ResultsController
时触发。我将尝试设置观察者,看看我能学到什么。感谢您的建议。由于加载和卸载不同的视图控制器,我在尝试侦听通知时感到困惑,因此我在托管对象子类中添加了一个willSave
。有趣的是,它在我调用[self.detailItem.managedObjectContext save:&error]
后立即被调用,正如预期的那样,但大约10秒后,我没有做任何事情,它又被调用了。如果我在第二个程序之前终止该程序,那么下次运行应用程序时,数据库中不会出现更改!尝试查看或发布第二个通知的堆栈跟踪,以便您可以确定它来自何处。好的,查看堆栈跟踪有太多我无法识别的内容。我将把它们附在上述问题之后。我还研究了NSManagedObject
的hasChanges
属性、包含它的NSManagedObjectContext
,以及parentContext
它们从+、+、-到-、-、+(++==true/hasChanges和-==false/!hasChanges)关于我的保存,因此我怀疑我看到的延迟保存是来自parentContext
的NSFetchedResultsController
已经有一个委托