• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: NSUndoManager setActionName: oddity
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: NSUndoManager setActionName: oddity


  • Subject: Re: NSUndoManager setActionName: oddity
  • From: Michael Babin <email@hidden>
  • Date: Mon, 02 Jul 2012 10:23:10 -0500

On Jul 2, 2012, at 4:35 AM, Conrad Shultz wrote:

> -My model contains an NSMutableArray
> -An NSArrayController has its content bound to said NSMutableArray and is configured to prepare content (which takes the form of another custom model object)
> -Said NSMutableArray is mutated only through the safe NSArrayController methods (-add:, -remove:, etc.)
>
> Everything works just fine, including undo and redo, which I manage by adding appropriate -prepareWithInvocationTarget: calls in the model's -insertObject:in[PropertyName]AtIndex: and -removeObjectFrom[PropertyName]AtIndex: methods.
>
> Now, I want to give the undo actions nice names.  To maintain a good MVC pattern I created wrapper action methods in my controller class (not the NSArrayController, but a custom NSViewController subclass that manages a variety of behaviors) such as:
>
> - (void)addRecord:(id)sender
> {
>    if (! [[self undoManager] isUndoing]) {
>        [[self undoManager] setActionName:NSLocalizedString(@"Add Record", nil)];
>    }
>    [[self arrayController] add:sender];
> }
>
> - (void)removeRecord:(id)sender
> {
>    if (! [[self undoManager] isUndoing]) {
>        [[self undoManager] setActionName:NSLocalizedString(@"Remove Record", nil)];
>    }
>    [[self arrayController] remove:sender];
> }
>
> and have my buttons, menu items, etc., call these wrapper methods.
>
> Here's the strange part: the action name appears to only have an effect in the *removal* case, never in the *addition* case.
>
> To be clear: everything else works fine.  If I perform an action triggering -addRecord:, the record *is* added and a functional undo action *is* registered, just with no action name.  But this only happens in the addition case - in the removal case, everything works *including the action name*.
>
> (If I move the -setActionName: into the model layer (-inserObject:…) the action name also works.)
>
> For debugging, I have verified that the expected code is called in the controller layer, and that the undo manager is both non-nil and is the same undo manager instance as used in the model layer.  Indeed, I can even see that the action name has been purportedly set when stepping through the code:
>
> (lldb) po [[self undoManager] undoActionName]
> (id) $1 = 0x00000001045f1520 Add Record
>
> But this never appears in the UI.  I also set a global breakpoint on [NSUndoManager setActionName:] and can see that it's only getting called once, inside my -addRecord: method.  So it doesn't seem to be getting clobbered later on.
>
> I have even been able to reproduce this behavior in a minimal test project (mashing together the model and controller layers), which you can download from:
>
> https://dl.dropbox.com/u/5847625/BindingsUndoTest.zip
>
> So my questions are severalfold:
>
> 1) Has anyone else seen this and can explain what's going on?  Have I missed something?
>
> 2) Can anyone suggest a workaround, preferably short of moving -setActionName: into the model?
>
> 3) Is there perhaps a more appropriate way for me to handle undo/redo in this context?
>
> This is on OS X, 10.7.4, FYI.  I am targeting Lion.

I believe you're not seeing the "Add Record" action name because you're setting the action name for the current undo group in one iteration of the runloop and the action itself (-[NSArrayController add:]) is taking place in another iteration of the runloop (with a different undo group).

https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/UndoArchitecture/Articles/UndoManager.html

"NSUndoManager normally creates undo groups automatically during the run loop. The first time it is asked to record an undo operation in the run loop, it creates a new group. Then, at the end of the loop, it closes the group."

https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSArrayController_Class/Reference/Reference.html

Under "Special Considerations" for add:

"Beginning with Mac OS X v10.4 the result of this method is deferred until the next iteration of the runloop so that the error presentation mechanism (see Error Responders and Error Recovery) can provide feedback as a sheet."



_______________________________________________

Cocoa-dev mailing list (email@hidden)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:

This email sent to email@hidden


  • Follow-Ups:
    • Re: NSUndoManager setActionName: oddity
      • From: Conrad Shultz <email@hidden>
References: 
 >NSUndoManager setActionName: oddity (From: Conrad Shultz <email@hidden>)

  • Prev by Date: Re: How to copy class interface and implementation without connections to .xib file
  • Next by Date: Re: NSUndoManager setActionName: oddity
  • Previous by thread: NSUndoManager setActionName: oddity
  • Next by thread: Re: NSUndoManager setActionName: oddity
  • Index(es):
    • Date
    • Thread