The Shape of Everything
A website mostly about Mac stuff, written by Gus Mueller
» Acorn
» Twitter
» Maybe Pizza?
» Code
» Archive
March 14, 2011

I've talked in the past about testing with JSTalk, and in that post I had a little snippet of code that looked like this:

PXWithUndo(doc, function() {
    [[win canvas] placeBezierRectOnMask:NSMakeRect(0, 50, 30, 30)];
});

PXWithUndo(doc, function() {
    // do something else that's undoable
});

The idea being that I call multiple operations in quick succession (from JSTalk) and then test each of those undos and make sure the state is exactly what it should be. I recently came across an instance where I needed to do the same thing in Objective-C code, so I thought I'd share with my fair readers the solution I came up with (experienced Obj-C coders will probably know right away what the solution is).

This is what I want my test code to look like:

[[self document] withUndo:^{
    [self placeBezierRectOnMask:NSMakeRect(0, 50, 30, 30)];
}];

[[self document] withUndo:^{
    // do something else that's undoable, etc.
}];

So to make this method a reality, I'm going to open up my document's header file and add a typedef at the top above my @interface:

typedef void (^TSWithUndoBlock)();

Next up, add the prototype to our document interface:

- (void)withUndo:(TSWithUndoBlock)block;

And then finally, in our document implementation:

- (void)withUndo:(TSWithUndoBlock)block {
    [[self undoManager] setGroupsByEvent:NO];
    [[self undoManager] beginUndoGrouping];
    block();
    [[self undoManager] endUndoGrouping];
    [[self undoManager] setGroupsByEvent:YES];
}

Tada. Simple, easy, and great for testing multiple undo operations.

Postscript: TS stands for "TinySketch". Post postscript: TinySketch was the original name for FlySketch. Moar postscript: FlySketch 2.0 turned into Acorn 1.0 because the FS upgrade got a bit out of hand. And to make a long postscript short, that's why Acorn's classes use the prefix TS.