Cocoa Swap

A fair number of my colleagues at Apple wouldn’t touch C++ with a ten-foot pole1. Which is a shame, because it has some good ideas.

One idea that’s stuck with me in the 8 years (8 years!) since I wrote my first draft of this post is std::swap().

You use std::swap() like so: instead of doing all your work on your actual objects, you do it on temporary objects instead. Reading in a file’s contents, making a change to your document, parsing a user’s input, it all happens detached from your data model. When the work, and all the possibilities for errors, have been slogged through, you use std::swap() to exchange the temporary objects’ content with that of the real objects.

This is important in C++ because codeflow-interrupting exceptions are a much larger part of error-handling, and because std::swap() is guaranteed not to throw.

Why should I care about this in Objective-C? After all, Apple’s developer documentation goes out of its way to discourage any use of exceptions for normal error handling, instead recommending that methods use NSError parameters2.

Let’s leave aside that it can be rather cumbersome to add an extra parameter to all of your methods, and to be sure deeply nested errors are passed all the way up. Even if no exceptions are thrown, if you encounter an error in the midst of complex changes to your data model, it can be tough to back all the changes out safely. Using temporaries reduces that risk to zero.

Is it worth it? You may, after all, wind up swapping out your entire data model if the changes you’re accumulating are extensive. If you’re working on a 4 GB image file, for example, then this technique probably isn’t for you.

And what if one of the things you’re changing is a file? Here, too, you can swap a temporary with the real thing in a way that’s virtually guaranteed never to cause problems—at least, if you’re willing to drop down a bit from the high-level Cocoa APIs and use Core Service’s FSExchangeObjects() method. (And are willing to bet that a method that uses FSRef types isn’t going to be deprecated. Hey, they ported it to iOS.) My understanding is that FSExchangeObjects() makes only HFS+ metadata changes, if the two files are on the same HFS+ partition. No worries about running out of disk space, permissions, etc. You can use it for ten files in a row, and they should all Just Work.

1. A fair number of my other colleagues at Apple were C++ fiends. ↩︎
2. “Instead of exceptions, error objects (NSError) and the Cocoa error-delivery mechanism are the recommended way to communicate expected errors in Cocoa applications.” ↩︎