Block initialization for testability and reuse
Since Apple introduced block support in iOS 4, more and more APIs are moving from delegation to block callbacks. While block callbacks can be declared inline, in most cases you should initialize your block callback in a method that returns the block. This keeps the code that calls an external API succinct, allows you to reuse the block in different contexts, and makes it easier to unit test the code in the block.
Let’s see what this looks like in practice.
Blocks as Return Values
One common API that uses blocks is UIView animation:
Using a method to create the animation block looks like this:
[self saveSomeData];
[UIView animateWithDuration:.5f animations:[self slideOffStageRight]];

}
-(void (^)(void))slideOffStageRight {
return ^ {
self.screen.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:.5f];
self.someView.frame = CGRectMake(UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ? 320 : 480,
Y(self.someView), WIDTH(self.someView), HEIGHT(self.someView));
}
};
}
There are a few nice things about this approach:
- It’s succinct. The code path you care about makes the call to fire the animation and continues. In this way, it’s very similar to delegation, where the code that handles delegate callbacks isn’t inline when you invoke the API.
- It’s idiomatic. It reads like a sentence–“animate off stage right”. What I care about when I look at
someButtonPressed
is the style of animation in use, not how it’s implemented. It’s also clear what the author intended, which is helpful when the result isn’t what you’d expect. - It’s reusable. If there are multiple places that could invoke this animation, you don’t repeat the block definition. And if there’s a bug in the animation block, you can fix it once.
- It’s testable. We’re big proponents of test-driven development. With this approach, you can invoke the animation block directly in a spec:
[controller slideOffStageRight]();
expect(controller.screen.backgroundColor).toEqual([[UIColor blackColor] colorWithAlphaComponent:.5f]);
expect(X(controller.someView)).toEqual(320);
});
Inline Blocks
The approach you’re probably most familiar with is initializing the animation block inline. Let’s see how that looks:
[self saveSomeData];
[UIView animateWithDuration:.5f animations:^{
self.screen.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:.5f];
self.someView.frame = CGRectMake(UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ? 320 : 480,
Y(self.someView), WIDTH(self.someView), HEIGHT(self.someView));
}];
}
It’s shorter, but it has a few drawbacks:
- It breaks the code’s flow. Reading the containing method, you suddenly hit this chunk of code that clearly animates something. But to understand how it animates, you have to build a mental model of the views and imagine the changes. Or you can ignore it. But you can’t just glance at it and think “Ok, it slides off to the right here.”
- It’s not reusable. If you need the same animation elsewhere, you’re likely to copy/paste the code. Then, when you change it, you’re likely to miss the other instance of the same animation.
- It’s hard to test. The only way to test it is to invoke the method surrounding method, block for the duration of the animation, and assert the resulting state. If the block defines a callback for some asynchronous API, it gets even more complicated.
Blocks as Properties
One pattern I see a lot is creating a block during initialization and storing it in a property. Here’s what this looks like with our example:
@synthesize slideOffStageRight;
-(id)init {
self = [super init];
if (self) {
__weak Foo *bself = self;
self.slideOffStageRight = ^{
bself.screen.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:.5f];
bself.someView.frame = CGRectMake(UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ? 320 : 480,
Y(self.someView), WIDTH(self.someView), HEIGHT(self.someView));
};
}
return self;
}
-(IBAction)someButtonPressed:(id)sender {
[self saveSomeData];
[UIView animateWithDuration:.5f animations:self.slideOffStageRight];

}
The property approach makes the block reusable, but it too has a couple of drawbacks:
- You have to beware of retain cycles. Note the
bself
variable. This is necessary because blocks automatically retain object variables they reference. If the block were to referenceself
directly, the block would increase self’s retain count when it’s created, creating a retain cycle. As a result, all instances of this object would leak unless the caller explicitly un-sets theslideOffStageRight
property. But callers shouldn’t have to worry about this object’s internal state. - It’s inflexible. What if you want to apply this animation to different views? If you create a block at initialization and store it in a property, it is what it is. With the method return approach, you can just modify the method to take the view to animate as an argument:
Summary
With advantages both over block properties and inline block definitions, I find that initializing reusable blocks in methods keeps me sane. The code is succinct and flexible, memory leaks are reduced, and the thorough test coverage keeps me confident that the code does what I expect it to. I encourage you to try this approach out and let me know what you think.
8 Comments
George Cook
October 19, 2012nice write up. I think it’s actually an improvement to what I frequently do (which is delegate the block to a method).
I’ll give it a roadtest and let you knowhow I get on.
Edward
October 23, 2012Do you lose the ability to access local variables that would be in scope if you declared the block inline? If so, do you consider this a disadvantage for blocks as a return value?
Christopher Pickslay
October 23, 2012Great question, Edward. You can easily define the method that returns the block to take an argument, and pass the local variable(s) into it. For example, say we wanted to slide any view off to the right. You could define the method as:
[self saveSomeData];
UIView *someView = [self getTheViewThatCorrespondsToButton:sender];
[UIView animateWithDuration:.5f animations:[self slideOffStageRight:someView]];

}
-(void (^)(void))slideOffStageRight:(UIView *)someView {
return ^ {
self.screen.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:.5f];
someView.frame = CGRectMake(UIInterfaceOrientationIsPortrait(self.interfaceOrientation) ? 320 : 480,
Y(someView), WIDTH(someView), HEIGHT(someView));
}
};
}
Edward
October 24, 2012Yup. That is definitely a solution that I considered to get around the issue. The only problem is that sometimes I’m working with a 3rd party library API that defines the block a method takes, and I wouldn’t have control over that. What would you do in that situation? Wrap their API with your own to take the arguments you need?
Christopher Pickslay
October 24, 2012I don’t think that’s any different. The third party API expects a block with a certain signature. But your method that returns that block can define its own signature, in terms of the arguments it accepts. So your call to the third party API might look something like:
[ThirdPartyAPI doSomethingWithCallback:[self callbackForString:someLocalString]];
Edward
October 28, 2012ah yup. I see what you mean now. awesome
James Frost
March 16, 2013Great post! Your approach helps to counteract one of my main issues with code that uses a lot of blocks – namely that methods get long and hard to read.
One quick question though – what is it about the first example that means there’s no retain cycle when using ‘self’ in the block?
Christopher Pickslay
March 18, 2013Thanks James. In the first example, the block is only created in response to some user interaction, and disposed of at the end of the animation. So
self
is only retained while the block is executed, which should be while UIKit sets up the animation.By contrast, when you store a block in a property, the block is created whenever you initialize the property, and not disposed of until the instance that references it is deallocated. If you inadvertently leave a strong reference to
self
in the block, the instance that owns it will never be deallocated, because the block prevents its retain count from going to zero. Before weak references became available in iOS 5, I saw lots of ugly code where people tried to determine that the object’s lifecycle was over, and set the block property to nil so the object could be deallocated.