CoreDataブラウジング用の一般的なビュー/クラスのセットがありますが、リストされたオブジェクトの1つの属性への変更を保存した後、フェッチされた結果コントローラーの並べ替え順序に問題があります。
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
テーブルビューコントローラーでは、次のような詳細テーブルビューコントローラーにプッシュします。
- (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には、各属性および各関係の行があります。属性を含む行が選択されている場合、 ManagedObjectAttributeEditViewControllerビューコントローラーにdidSelectRowAtIndexPath
プッシュします。
- (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にプッシュされます。値を変更して[保存]をタップします。これはManagedObjectDetailTableViewControllerにポップし、すべてが正常に表示されます。次に、戻るボタンをタッチしてエンティティのオブジェクトのリストに戻りますが、並べ替えられなくなりました(常に同じ順序になっているように見えますが、順序のパターンがわかりません)。
保存を行ってから戻るボタンを押す前に10まで数えると、リストは適切にソートされます。
[self.detailItem.managedObjectContext save: &error]
メソッド呼び出しをコメントアウトするdidSaveValue:forKey:
と、エンティティのオブジェクトのリストは正しくソートされたままになりますが、自動保存が発生する前にアプリケーションを終了すると、変更が失われます。
これは[self.detailItem.managedObjectContext save: &error]
、何らかの理由でソートされたデータを取得できないために、完了していないことと、フェッチされた結果コントローラー(同じNSManagedObjectContextを使用している)と関係があると思います。
値を変更する属性はソート記述子に含まれていないため、値を変更する前後で表示される順序は同じである必要があります。私のデータベースは非常に大きく、ディスクに書き込むのに数秒かかる場合があります。シミュレーターとデバイスでiOS5.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];
}
親コンテキストでは保存が1レベルしか上がらないため、最新のiOSでパーマネントストアに変更を加えるには、この二重保存が必要であることがわかりました。保存をパーマネントストアに伝播しないと、ソート順がスクランブルされる理由がわかりません。たぶん、私のコードのどこかに、これがマスキングしている、またはそれが機能する方法であるという他のバグがあるかもしれません...