Recursive Blocks

Blocks are a language-level feature for C, Objective-C and C++, which, among other things, allow passing code into methods as if it were a variable, or so Apple’s documentation says. Personally, I love blocks. They are convenient, non-blocking (ha-ha) and have a peculiar, but fun syntax.

It all becomes more fun when you have to pass a block between several functions, keeping track of what’s in scope and what isn’t.

Modern Objective-C is using ARC, which is more convenient for the user and more memory safe than what you have to do in C by hand. With simplicity, though, come a few caveats. One of them is a retain cycle, when two objects have strong pointers to each other, that is, while one exists, the other won’t be released. As they are referencing each other, they will both not be released and will clog up memory. Thus, retain cycles.

There are techniques that you can use to avoid them, for example using a weak reference, which means that a weak object only exists if someone is referencing it. As soon as the reference is gone, the object gets released from memory.

Anyway, I learned a new trick for block recursion, which doesn’t make the compiler wail and is easy to understand.

There are three obstacles on the way to block recursion:

  1. You can’t use the block within the same block until it has been fully initialized.
  2. You can’t use only a __block prefix on the block variable, because it creates a retain cycle.
  3. You can’t use only a __weak prefix on the block variable, because then it would be deallocated at the worst possible moment.

The solution is below:

__block __weak void (^weakNextPage)(void); // A weak block variable that we would use inside the block.
void (^nextPage)(void); // The block has to be fully initialized before recursive use, otherwise it would be NULL.
weakNextPage = nextPage = ^(void) { // Have weak and normal block variables point to the same code.
    if (finished) {
        block(YES);
    } else {
        currentPage++; // This is a __block variable declared just before the block declaration.
        weakNextPage(); // Call the block recursively.
    }
};

nextPage(); // Call the first iteration of the block.

Pretty simple, but it’s worth knowing. There’s also a website with a nice URL reminding on the syntax, which is not really straightforward. Oh well, they’re still a joy to use.

2014   iOS
Popular