Objective c NSUndoManager:在一个运行循环周期中分离多个更改

Objective c NSUndoManager:在一个运行循环周期中分离多个更改,objective-c,xcode,macos,cocoa,nsundomanager,Objective C,Xcode,Macos,Cocoa,Nsundomanager,我正在使用[undoManager registerUndoWithTarget::]向撤消堆栈添加一些更改。 然而,有时会发生这种情况,在一个运行循环周期中,两个更改添加到同一个组中,因此它们会立即恢复,这不是我想要的行为。 我想将这两个更改分开,以便在撤消堆栈中有两个项。 如何正确实施??使用[NSObject performSelector:]调用下一个运行循环周期中的第二次撤消添加,或其他任何操作 谢谢。正如您所注意到的,默认情况下,NSUndoManager会在一个运行循环周期内自动将

我正在使用[undoManager registerUndoWithTarget::]向撤消堆栈添加一些更改。 然而,有时会发生这种情况,在一个运行循环周期中,两个更改添加到同一个组中,因此它们会立即恢复,这不是我想要的行为。 我想将这两个更改分开,以便在撤消堆栈中有两个项。 如何正确实施??使用[NSObject performSelector:]调用下一个运行循环周期中的第二次撤消添加,或其他任何操作


谢谢。

正如您所注意到的,默认情况下,
NSUndoManager
会在一个运行循环周期内自动将撤消操作分组。您可以更改该行为,但是:
-[nsendomanager setGroupsByEvent::
将在发送
NO
参数时禁用自动分组。请注意,在撤消管理器执行
-undo
-undoNestedGroup
之前,需要确保所有组都已关闭。由于其他Cocoa类可能希望在不显式创建组的情况下注册撤消操作,因此可以在注册撤消组之前禁用自动分组,在注册这些组后重新启用

例如:

- (void)someMethod {
    NSUndoManager *undoManager = …; // for example, [[self window] undoManager]
    [undoManager setGroupsByEvent:NO];
    {
        [undoManager beginUndoGrouping];
        {
            [undoManager registerUndoWithTarget:modelObject selector:@selector(setString1:) object:[modelObject string1]];
            [modelObject setStringValue:newValue1];
            [undoManager setActionName:@"String 1 Change"];
        }
        [undoManager endUndoGrouping];


        [undoManager beginUndoGrouping];
        {
            [undoManager registerUndoWithTarget:modelObject selector:@selector(setString2:) object:[modelObject string2]];
            [modelObject setString2:newValue3];

            [undoManager registerUndoWithTarget:modelObject selector:@selector(setString3:) object:[modelObject string3]];
            [modelObject setString3:newValue3];

            [undoManager setActionName:@"Strings 2 and 3 Change"];
        }
        [undoManager endUndoGrouping];
    }
    [undoManager setGroupsByEvent:YES];
}
-someMethod
中,对
modelObject
应用了三个更改,即修改其
string1
string2
string3
属性。应用于
string1
的更改是撤消组的一部分,而对
string2
string3
的更改是另一撤消组的一部分。这两个组都包含在一个块中,在该块中,撤消管理器不会对当前运行循环的默认撤消组中的所有操作进行分组。执行此方法后,第一个撤消操作撤消
string2
string3
更改,随后的撤消操作撤消应用于
string1
的更改,前提是没有另一个撤消组包含它们

我使用C块
{}
来清除这两个层次结构(不按事件分组和撤消组)


注意:
NSUndoManager
不是线程安全的。

谢谢你的回答。问题的另一部分(我应该在问题中提及)是,撤销注册消息的一部分是由NSTextView发送的,我无法控制。@NickolayOlshevsky,您面临的确切问题是什么?我用
NSTextView
编写了一个快速应用程序,它似乎工作得很好:文本视图撤消操作被放置在撤消堆栈上,并且与我的自定义撤消组分开。我正在NSTextView中编辑一些文本,这会记录撤消(“撤消键入”)。之后,我将该项拖动到其他位置,并注册此拖动的撤消操作。这种拖拽+文本输入被记录为撤销。谢谢你花时间看这个。@NickolayOlshevsky你认为你可以发布一个展示这种行为的小样本项目吗?我愿意看一看。您正在主线程上注册撤销组吗?哦,稍后我将尝试在示例项目中复制此内容。目前,该项目正在向大公司发起,试图在合理的时间内从中删除一些内容。是的,一切都在主线程上工作,我不创建任何工作线程。并且不调用任何分组方法-只需[undoManager RegisterEndo:]