In general, I prefer using block-based APIs over those that accept selectors.
The block based APIs are generally easier to read & follow, and don’t clutter up your class with methods that are out of context with the code that might potentially invoke them.
One good example is view animations. Here we’re fading out a view and removing it from the hierarchy once the view has been completely faded out. It’s concise, easy to read, and you don’t need to go anywhere else in the class to get a complete picture of how this works.
Also, since you can have multiple animations going on, having a block-based completion handler means you don’t have to distinguish between what the animations were in some generic completion method.
1 2 3 4 5
Contrast this with the non-block version:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
Block-Based Notification Handlers
NSNotificationCenter also got some block love when iOS SDK 4.0 came around. The old form looked like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
This isn’t a lot of code (and it is easy to remember, unlike the previous UIView animation block code), however the action and the notification handler are separated from each other.
The block-based API looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Aside from some funky indentation, this is preferable in some cases, especially when the action to be completed is as simple as reloading the table.
But there’s a bug. Can you spot it?
Blocks Are Closures
There’s a subtle bug here that you might not notice at first. I didn’t realize this until it was littered all over my code base.
Blocks are closures, and they will capture any values declared outside the scope of the block (and retained) so that they can be used when the block executes. This includes variables declared in the enclosing method or any ivars that you reference from inside the block.
Here, we used
self gets retained by the block, which is also retained by self. We have a retain-cycle
which is generally a bad thing. It’s especially bad here, because we don’t clear out the block until
but dealloc won’t ever be called because the block is retaining the instance!
Weak Pointers Save the Day
If you’ve read up on blocks, you’ve probably seen the
__block keyword. This specifier tells blocks not to retain the pointer.
So all we need is a new pointer, like so:
1 2 3
This sort of code drives me nuts. It won’t be apparent to the next developer why it’s there, and it’s pretty ugly.
Retain Cycles are Elsewhere, Too
You might also run into this if you have a parent-child view controller relationship, or perhaps a
an parent->object->delegate chain, where the parent is the delegate. This is why you typically mark
your delegate property signatures with
assign instead of
Not all retain-cycles are terrible though. If you have a way of breaking the cycle, then you just need to weigh how long these objects will remain active for to decide if you need to fix it.
Hopefully this will save you a few headaches down the line.