2

appointment属性を編集するNSManagedObjectという名前があります。ユーザーがキャンセルを押した場合、それらの編集をすべて元に戻したいと思います。

もしそうなら(サンプルコード)

[[appointment managedObjectContext] setUndoManager:[[NSUndoManager alloc] init]]; //however doing a nslog on undoManager still shows it as (null);
[[[appointment managedObjectContext] undoManager] beginUndoGrouping];
appointment.startTime = 11;
appointment.endTime = 12;
appointment.customer = @"Tom";
[[[appointment managedObjectContext] undoManager] endUndoGrouping];
[[[appointment managedObjectContext] undoManager] undo];

beginUndoGroupingとの間のすべての変更変更を元に戻すべきではありませんendUndoGroupingか?これを行うには多くの方法があるようですが、正しい方法を見つけることができないようです。上の変更を元に戻す正しい方法は何NSManagedObjectですか?

4

2 に答える 2

7

これはイベントが進行する順序の単なる例であり、実際の例ではないと思います.

たまたま、ManagedObjectContext に NSUndoManager を与えるのを忘れていませんか?

OS X ではデフォルトで 1 つ取得できると思いますが、iOS では特に指定する必要があります。

MOC を作成するときは、必ず元に戻すマネージャーを設定する必要があります...

managedObjectContext.undoManager = [[NSUndoManager alloc] init];

undo-manager が nil の場合、これを行った後、複数の MOC を使用しているか、他のコードによってリセットされています。

また、デバッグのために、appoint.managedObjectContext プロパティをチェックし、それが nil ではなく、有効な MOC を参照していることを確認してください。

編集

わかりました、単純なモデルを使用して簡単なテストを書きました。おそらく、アサーションがどこで失敗しているかを確認するために、同様のことを行う必要があります(コードパスに通常のアサートを追加するだけです-これを単体テストとして行ったので、既存のプロジェクトに簡単に追加できました)。

- (void)testUndoManager
{
    NSDate *now = [NSDate date];
    NSManagedObjectContext *moc = [self managedObjectContextWithConcurrencyType:NSConfinementConcurrencyType];
    STAssertNil(moc.undoManager, @"undoManager is nil by default in iOS");
    moc.undoManager = [[NSUndoManager alloc] init];
    [moc.undoManager beginUndoGrouping];
    NSManagedObject *object = [NSEntityDescription insertNewObjectForEntityForName:EVENT_ENTITY_NAME inManagedObjectContext:moc];
    STAssertNotNil(moc, @"Managed Object is nil");
    STAssertEquals(moc, object.managedObjectContext,  @"MOC of object should be same as MOC");
    STAssertNotNil(object.managedObjectContext.undoManager, @"undoManager of MOC should not be nil");
    [object setValue:now forKey:@"timestamp"];
    STAssertEqualObjects(now, [object valueForKey:@"timestamp"], @"Timestamp should be NOW");
    [moc.undoManager endUndoGrouping];
    STAssertEqualObjects(now, [object valueForKey:@"timestamp"], @"Timestamp should be NOW");
    [moc.undoManager undo];
    STAssertNil([object valueForKey:@"timestamp"], @"Object access should be nil because changes were undone");
}

編集

管理対象オブジェクトの MOC は、いくつかの条件下で nil に設定できます。たとえば、オブジェクトを削除してから mod を保存すると、そのオブジェクトの MOC は nil に設定されます...

NSManagedObject *object = [NSEntityDescription insertNewObjectForEntityForName:@"SomeEntity" inManagedObjectContext:moc];
[object.managedObjectContext deleteObject:object];
[moc save:0];
// object.managedObjectContext will be nil

もう 1 つのあまり一般的ではないケースですが、MOC にメモリの問題がある可能性を示す兆候です... ARC では、管理対象オブジェクトの MOC は弱いポインターです。したがって、MOC がなくなると、そのポインターは nil にリセットされます。非 ARC では、ポインターは古い値を持つだけで、結果は未定義になります...おそらくクラッシュします。

したがって、managedObject.managedObjectManager が nil の場合、最も可能性の高い原因は次のとおりです。

  1. オブジェクトは MOC に挿入されませんでした
  2. オブジェクトは MOC から削除されました
  3. MOC が削除されました
于 2012-04-24T21:55:10.173 に答える
0

元に戻すが Core Data で機能しない最大の理由は、元に戻すマネージャーを作成および設定していないことです...

 newManager = [[[NSUndoManager alloc] init] autorelease];
 [newManager setLevelsOfUndo:4];
 myManagedObjectContext.undoManager = newManager;

また、Begin/end undoGrouping も必要ありません。これは自動的に行われるためです。

また、イベント ループに戻って次に呼び出されるまで、元に戻す操作が機能しない可能性もあります (部分的には、それが自動的に行われるためです)。(つまり、ユーザーが元に戻すボタンを押すのをカットしても機能しない場合があります。)

ああ、あなたは上のコメントを追加しました。undoManager が null であると明らかに機能しないため、設定を行うコードを投稿してください。

于 2012-04-24T22:23:01.880 に答える