I have a Document which has a meeting. When I initialize the meeting, I set the undoManager to point to the Document's undoManager. Likewise, my meeting has attendees (list of Person). Each Person object simply points back to my meeting's undoManager which in turn is just a pointer to the Document.
My undo for adding and removing attendees to the meeting was working until I started observing the key values for attributes of the person.
Any ideas on what I am doing wrong? When I add and remove an attendee, the undo button does not activate. Likewise, when I make a change to the person's name/rate, the undo button does not show up.
Document.m
- (id)init
{
self = [super init];
if (self) {
self.meeting = [[Meeting alloc] init];
self.meeting.undoManager = self.undoManager;
meeting.h ---
@property (nonatomic, retain) NSUndoManager *undoManager;
meeting.m
- (void)changeKeyPath:(NSString *)keyPath
ofObject:(id)obj
toValue:(id)newValue {
// setValue:forKeyPath: will cause the key-value observing method
// to be called, which takes care of the undo stuff
[obj setValue:newValue forKeyPath:keyPath];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context {
id oldValue = [change objectForKey:NSKeyValueChangeOldKey];
// NSNull objects are used to represent nil in a dictionary
if (oldValue == [NSNull null]) {
oldValue = nil;
}
[[self.undoManager prepareWithInvocationTarget:self] changeKeyPath:keyPath
ofObject:object
toValue:oldValue];
// Notify the undoManager
self.undoManager.actionName = @"Edit";
}
- (void)startObservingPerson:(Person *)person {
// TODO: Understand if I need something for context
[person addObserver:self
forKeyPath:@"name"
options:NSKeyValueObservingOptionOld
context:nil];
[person addObserver:self
forKeyPath:@"rate"
options:NSKeyValueObservingOptionOld
context:nil];
}
- (void)stopObservingPerson:(Person *)person {
[person removeObserver:self forKeyPath:@"name"];
[person removeObserver:self forKeyPath:@"rate"];
}
-(void) insertObject:(id *)object inAttendeeListAtIndex:(NSUInteger)index {
[(Person *)object setMeeting:self];
// Enable undo capabilities for edits to the name/rate
[self startObservingPerson:(Person *)object];
// insert the object / person
[self.attendeeList insertObject:(Person *)object atIndex:index];
//
// configure the undo for the insert
[[self.undoManager prepareWithInvocationTarget:self] removeObjectFromAttendeeListAtIndex:(NSUInteger) index];
undoManager.actionName = @"Insert Person";
}
-(void) removeObjectFromAttendeeListAtIndex:(NSUInteger)index {
Person *deletedPerson = [self.attendeeList objectAtIndex:index];
// housecleaning before removing the person
[self stopObservingPerson:(Person *)deletedPerson];
// remove the object / person
[self.attendeeList removeObjectAtIndex:index];
// configure the undo
[[self.undoManager prepareWithInvocationTarget:self] insertObject:(id *)deletedPerson inAttendeeListAtIndex:index];
// Notify the undoManager
undoManager.actionName = @"Remove Person";
}
I found the answer to my problem. I initialize meetings one of two ways. New documents and through archived documents. When I was loading from the archive, I wasn't assigning the undoManager so it was null and nothing was happendi