我有一组用于 CoreData 浏览的通用视图/类,但是在保存对列出对象之一的属性的更改后,我的获取结果控制器的排序顺序有问题。
在viewWillAppear:
我的表格视图控制器中,我将获取的结果控制器设置为:
- (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 */
}
在didSelectRowAtIndexPath
这个 tableview 控制器中,我推送到一个详细的 table view 控制器,如下所示:
- (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每个属性和每个关系都有一行。如果选择了包含和属性的行,didSelectRowAtIndexPath
我会推送到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];
}
因此,如果我从实体的对象列表开始,并且它们已正确排序。我触摸一行并将其推送到ManagedObjectDetailTableViewController。我触摸其中的一个属性行,它会推送到ManagedObjectAttributeEditViewController。我更改值并触摸save。这会弹出到ManagedObjectDetailTableViewController,一切看起来都很好。然后我触摸后退按钮以返回实体的对象列表,但现在它们不再排序(它们似乎总是按相同的顺序,但我不认识该顺序的模式)。
如果我在保存后并且在触摸后退按钮之前数到 10,则列表已正确排序。
如果我注释掉[self.detailItem.managedObjectContext save: &error]
方法调用,didSaveValue:forKey:
则实体的对象列表保持正确排序,但如果我在自动保存发生之前退出应用程序,我会丢失更改。
这让我认为这与[self.detailItem.managedObjectContext save: &error]
未完成和获取的结果控制器(使用相同的 NSManagedObjectContext)由于某种原因无法检索排序的数据有关。
我要更改的属性值不涉及排序描述符,因此在我修改值之前和之后显示的顺序应该相同。我的数据库非常大,可能需要几秒钟才能将其写入磁盘。我在模拟器和设备上看到了 iOS 5.1 的问题。
有没有人经历过这样的事情或有什么建议?
抱歉,对于美国的所有 Stackoverflowers 来说,7 月 4 日如此冗长而快乐!
修改后的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" );
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 将其更改为永久存储是必要的,因为在父上下文中,保存只会上升一个级别。我不明白为什么不将保存传播到永久商店应该打乱排序顺序。也许我的代码中的某个地方还有其他一些错误,这是掩盖的,或者它只是它的工作方式......