I just bought a new camera body.

That doesn't sound like it's worth a blog post, but this is a big deal for me: this is my first brand new SLR in a hobby that's spanned sixteen years. While I try to share the results of my efforts, I've never written about my history with the craft.


Amsterdam was a great combination of visiting old friends, making new friends, and meeting old friends for the first time, all wrapped up in an incredibly unique and beautiful city. But perhaps most importantly, Cindy got some pony time.


I'm a bit late catching up on feeds, but I came across Brent Simmons' post on Coalescing today and—having solved the same problem in a different way—thought I'd chime in.

Coalescing calls is great for things like data stores that are backed by an archive on disk, because you want every operation to call -synchronize when it's finished (for data integrity), but you also don't want it to be over-called (for performance). In my own use today, coalescing saved 75% of the disk writes in my test harness which, while obviously a contrived case, proved its usefuless immediately.

In my own limited experience, NSTimer or -performSelector:afterDelay: are a code smell1, and their use should be eliminated and replaced with something that is more appropriate to the problem being solved. In unit testing, I use dispatch_group to block tests until the side effects (in this case, delegate calls) have been completed as expected. For call coalescing—since I'm already using GCD for mutexing—I simply add a counter:

// Called on lockQueue, a serial dispatch queue.
- (void)synchronize;
{
    self.syncCount++;

    dispatch_async(lockQueue, ^{
        if (--self.syncCount == 0) {
            // Do your work here.
        }
    });
}

Super simple, and if you're already using dispatch queues for locking, which I highly recommend, all you need to add is a property. For a minor performance boost (avoiding Block_copy) replace dispatch_async with dispatch_async_f and the appropriate glue.


1 Although I can see an argument for their use for UI/animations, more often they're used to try to avoid race conditions that aren't understood or to queue something to run after the main thread's runloop has finished its current iteration2.
2 For which you should be using dispatch_async(dispatch_get_main_queue(), ^{ /* … */}) instead.