views:

41

answers:

2

Hi,

I'm experiencing problems with the undo operation. The following code won't undo an removeObjectForKey: operation but the redo operation setObject:ForKey: works.

 - (void) insertIntoDictionary:(NSBezierPath *)thePath
{
 [[[window undoManager] prepareWithInvocationTarget:self] removeFromDictionary:thePath];

 if(![[window undoManager] isUndoing])
  [[window undoManager] setActionName:@"Save Path"];

 NSLog(@"Object id is: %d and Key id is: %d", [currentPath objectAtIndex:0], thePath);

 [colorsForPaths setObject:[currentPath objectAtIndex:0] forKey:thePath];
}

- (void) removeFromDictionary:(NSBezierPath *)thePath
{
 [[[window undoManager] prepareWithInvocationTarget:self] insertIntoDictionary:thePath];

 if(![[window undoManager] isUndoing])
  [[window undoManager] setActionName:@"Delete Path"];

 NSLog(@"Object id is: %d and Key id is: %d", [colorsForPaths objectForKey:thePath], thePath);

 [colorsForPaths removeObjectForKey:thePath];

}

The output on the console looks like:

// Before setObject:ForKey:
Object id is: 1183296 and Key id is: 1423872

// Before removeObjectForKey:
UNDO
Object id is: 0 and Key id is: 1423872

I don't get why the Object id is different although the Key id remains the same. Is there some special undo/redo handling of NSMutableDictionary objects?

thx xonic

+1  A: 

In one example you're logging the address of [currentPath objectAtIndex:0], and in the other you're logging the address of an arbitrary key (not even a value, but a random key) from the dictionary. There's no reason I can see in the code why these should be the same thing.

Chuck
ah darn, sorry about that... had a left over snippet from playing around with the code. I'm getting tired, I guess :)I've now corrected the code, the result however is still not working.Thx
xon1c
+2  A: 

It sounds like NSUndoManager is doing it's job, but when it's time to remove the value there's no object in the dictionary for the NSBezierPath key. My guess is that NSBezierPath isn't safe to use as a dictionary key. The NSBezierPath object you're using as a key is probably being mutated somewhere in between assignment and undo, which means its hash method is different by the time you reach removeFromDictionary:, and you no longer have a meaningful dictionary key. Instead, try using an NSString or NSNumber that's somehow associated with the bezier path as a dictionary key.

Marc Charbonneau
Thx for your input. Actually I'm not sure whether that's really the problem. On one hand I do have the same call [colorsForPaths objectForKey:thePath] in a different file (the view) which returns the correct object, but on the other hand the redo operation logs the correct NSBezierPath id and inserts the correct object in the dictionary even though that object is then twice in the dictionary and not overwritten by the new, redone (same) object.
xon1c