On 07 May 2012, at 4:45 pm, Graham Cox wrote:
> Another way to 'centralise' undo is to have an object listen for the KVO
> notifications of changes for properties it's interested in, and use the
> observation method to record to the undo manager. You'd still use
> setValue:forKey: at undo time, so it amounts to a very similar idea. I've
> done it that way and it works.
Well, that would require my controller to -addObserver:... on each of the
collected objects, which I had earlier decided to avoid for various reasons.
But that's a good technique for me to keep in mind, and is beginning to sound
like possibly a better approach.
> So your problem must be something else. Are you sure undoManager returns
> something?
You're right, I deked myself out; I was trying to examine changes to a property
that was changed via the setter of a different property, but setValue:forKey:
was not being called for the former. I wasn't looking closely enough at the
call stack or the forKey: parameter when I saw the seemingly do-nothing
undoManager line dutifully execute.
But, that's sort of moot because as you point out...:
> Also, more obvious now I come to think about it, is that setValue:forKey: is
> not called for every property when it is set! That method can be used to call
> down to the setter for a named property, but if the setter is invoked
> directly (the more usual case), then setValue:forKey: isn't invoked. You
> might want to check whether that is what's happening. In which case making
> your undo handler a KVO observer will get around that problem, or you could
> override -willChangeValueForKey: instead, which is the method that causes
> some of the KVO "magic" to happen.
Much better idea, thanks. Moving my undo registration shim into
-willChangeValueForKey: solves the problem nicely:
- (void)willChangeValueForKey:(NSString *)key
{
// Register the inverse action if we are about to change an undoable
property.
if ([[FAEditorNote undoableKeys] containsObject:key])
[[undoManager prepareWithInvocationTarget:self] setValue:[self
valueForKey:key] forKey:key];
[super willChangeValueForKey:key];
return;
}
Which allows me to turf this gnarly macro I briefly purpose-built in the
interim:
#define DEFINE_UNDOABLE_COPYING_SETTER(SETTER,PROPERTY) \
- (void)SETTER(id)newValue \
{ \
if (newValue != PROPERTY) \
{ \
[undoManager registerUndoWithTarget:self
selector:@selector(SETTER) object:PROPERTY]; \
[PROPERTY release]; \
PROPERTY = [newValue copy]; \
} \
}
DEFINE_UNDOABLE_COPYING_SETTER(setPgmInTC:, pgmInTC);
DEFINE_UNDOABLE_COPYING_SETTER(setPgmOutTC:, pgmOutTC);
//etc.
thanks!
b
--
Ben Kennedy, chief magician
Zygoat Creative Technical Services
http://www.zygoat.ca
_______________________________________________
Cocoa-dev mailing list ([email protected])
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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com
This email sent to [email protected]