Some caveats for using C Blocks

One audacious thing that Apple does when it releases Mac OS X 10.6 is it adds block support into the C language. It's pretty much like what you expect—first-class objects that can be passed as function parameter and saved for later use. C aficionados now don't have to envy C++0x—if they're happy with the fact that it's an Apple-only extension for now (Apple is advocating the addition of the extension to the C language).

It's pretty fun. Read Mike Ash's article for a summary of what blocks do. I just want to point out some gotchas:

  1. Blocks live on your local stack. Fine if you pass them as function/method arguments in a local scope. If you want to toss them around, say save them for later use, you must make a copy.

  2. Copying a block has the side-effect of making a copy of its current local variables. These local variables are henceforth consts by nature when the copied block is later invoked. This is a very important point to bear in mind. See the usage for __block modifier if you need vars to live beyond such local scope1.

  3. Objective-C objects inside a block are implicitly retained when the block is copied. The compilers supplied by Apple are smart enough to produce codes that send -retain to all local variables that represent Objective-C objects (in short, all ids) in a managed setting (i.e. non-gc) when you copy a block2, so you really have something very close to a closure. On the other hand, objects are retained, not copied (it's the pointer values that get copied, copy that?), so make sure you don't fiddle with those objects unless you really want to (e.g. sending addObject: to an NSMutableArray object)—it might surprise you.

  4. If you want to pass a block to a property, make sure you have declared the property as copy. No, retain won't work, for reasons (1.) and (2.). You must use the copy attribute even if you are using gc.

  5. Yes, you need to remember to release the blocks if yours are copies, unless if you're using gc.

  6. Debugging is gapless. Simply set breakpoints inside any block. The only exception that I've run into so far is when you forgot to copy a block, and you use the objects pointed by the local vars—there you get really bizarre crashes and the debugger is stopped in the middle of nowhere. You're warned.

The block syntax has its own irregularities (different when you're declaring a method argument, for example), but once you get past and get used to that, it really becomes part of the code's blood. And at least in my case I couldn't imagine how I ever lived without it. After all, many other languages already have it for ages—they are nothing new! Finally ye olde C has it. I do hope this extension will get accepted in the industry—standardization takes long time, but it should be a good one to add to the language.

  1. This has consequences for C++ and Objective-C++ code that uses block. Copy constructors are invoked for C++ objects that live on a block's stack when a block is copied. More about that in Apple's document. 

  2. This isn't explained explicitly by Apple's own document. If you go to read Mike Ash's article, there's a discussion about this buried deep in the comment thread. I've done the experiments and confirmed it behaves as such.