3

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でパーマネントストアに変更を加えるには、この二重保存が必要であることがわかりました。保存をパーマネントストアに伝播しないと、ソート順がスクランブルされる理由がわかりません。たぶん、私のコードのどこかに、これがマスキングしている、またはそれが機能する方法であるという他のバグがあるかもしれません...

4

1 に答える 1

1

OK、新しいスタック トレースを含む編集に基づいて:

UIManagedDocument を使用して、コア データ スタックを管理しています。つまり、最初の保存はおそらく UIDocument のメイン スレッド コンテキストからのもので、2 回目はそのバックグラウンド コンテキストからのものです。UIManagedDocument の managedObjectContext コンテキストからオブジェクトを使用していることを確認できますか (自分で作成している他のコンテキストとは対照的です)。

別物。あなたの方法entitySortDescriptorListで何とかnilになっていないことを確認できますか?setupFetchedResultsController

最後に、その他の診断として:

  • save:最上位のビュー コントローラーから呼び出してみて、何が起こるかを確認してください。
  • NSFetchedResultsController のデリゲートを作成するとどうなりますか? 変更通知は届きますか?彼らは合理的に見えますか?
于 2012-07-04T20:37:16.427 に答える