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 (Cocoa-dev@lists.apple.com) 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 arch...@mail-archive.com