Practical Guide To Objective-C Blocks

Objective-C blocks are still fairly new feature to the language. They are not as simple as they could be, and they don’t work on older iOS versions (only 4.0 and above). This is probably why you don’t see them used that widely.

However, I don’t care about old iOS versions. Blocks can be extremely useful in certain cases, which is why you probably want to master them.

This week I spent countless hours learning them by changing couple of core things in my game to support them, while seemingly getting them to work right away, I faced afterwards some complicated memory issues, so I decided to write a tutorial to explain how to use them.

1. Basic definition

Normally blocks in are defined as follows:

If you have used C function pointers, you may notice blocks don’t differ from them much syntactically. The only difference with them is actually ^ instead of * mark. (Of course, they are functionally quite different)

Here’s a working example:

2. ALWAYS typedef

You probably noticed that the above looks very ugly and is tedious to write. However, there’s a solution.

Please, do this always, for your own sake. Besides of improving readability, it also allows you to change the definition in just one place. You can create a header file import it in the files it’s necessary.

3. Block’s variables and scope

Block can see variables inside the current scope. This is one reason they are very useful, because you don’t have to think what values to pass as parameters. However, they will also retain them, so it’s a easy way to run into problems. Use with care!
Also, blocks can not change variables unless you define them as __block.

Note! self being retained is easy way to cause memory leaks!
For example:

So, never use self inside the block!

4. Blocks as method parameters

At some point, you probably want to pass a block as a parameter to method. The syntax goes as follows, but this is a good reason to use typedefs

Also, Objective-C programming guidelines state that block should always be the last argument. This is purely a readability issue, because imagine the following:

As you can see, the last two variables after the block are difficult to notice.

5. Memory management

This is probably the most difficult thing about blocks. Essentially they are like all normal Objective-C objects, but there are some things to keep in mind.

Blocks are always created to stack. This means that they disappear when out of scope. This is why, when you want to save your block for later use, you have to copy it. When you copy the block, it is copied to heap.

There are couple of ways for handling this properly.

What you should use depends on what you are doing. Since this is a simple guide, I won’t go into details here. Instead, I recommend storing blocks with @property:

Okay, I mastered blocks, but what’s the point?

Are they complicated? Probably.
Are they necessary? No.
Are they cool and useful? Yes.
Can they make code easier to understand and more efficient to write? Yes, absolutely!

Personally I think they make code much easier to read. You can define simple action related to object at the same scope the object is created, instead of defining a separate method. Another reason is that you don’t have to pass tons of variables, since it has read-only access and can have read-write the variables in the scope it’s created in. Third reason is that they are flexible to change since they don’t require separate methods and protocols.

Whether to use them or not depends on what you are doing. I’m using them for smallish updater methods, animations, observer patterns, etc and find them very good for that. Yet, I probably wouldn’t use them for everything, especially very complex things.

One Response to “Practical Guide To Objective-C Blocks”

  1. Peter Jenkins

    When trying out this example:

    // This defines PrinterBlock as a pointer to block similar to the above.
    typedef void (^PrinterBlock)(NSString*);

    // Now you can use it like
    PrinterBlock print = void ^(NSString *str) { NSLog(str); };

    I got a compiler error Expected expression. Removing the word void in the second code line fixed it. Tested using Xcode 5.0.2 and 5.1 Beta 4 and got the same behavior.

    Reply

Leave a Reply