Blog Archives

More about block pitfalls

Conrad Stoll tweeted me a great article he wrote about a complicated pitfall he ran into while working with NSBlockOperation.  Check out this great real-world example of retain cycles and how to resolve them:

Advertisements

A Quick Gotcha About Blocks

Blocks are a great addition to the iOS SDK and C standard, especially for predominantly event driven applications as we commonly see on the iPhone and iPad.  There’s a quick gotcha that a junior developer here at Mindgrub reminded me of the other day.

While blocks are a powerful tool, if you’re not careful they can start to degrade the quality of your app by introducing retain cycles.  Retain cycles occur when two objects in your application keep strong references to one another.  Take the common table view for example.  Ordinarily, the view controller containing (owning) the table view acts as the datasource and delegate for table, providing the necessary information for displaying the number of rows and supplying cell objects.  If you look closely at the properties on UITableView for datasource and delegate, you’ll see that both properties are declared as “assign” or “weak” in ARC.  This is critical particularly in the case where the view controller is also the datasource/delegate.  If the properties were “strong” or “retain” you could easily wind up in a retain cycle where neither your UITableView nor your view controller would ever be destroyed, thereby leaking memory.

This can happen with blocks as well and it’s not always so obvious.  Let’s say we have a view for which we define a block to handle the user tapping it.  The code might look something like this:


#import <UIKit/UIKit.h>

typedef void(^TapBlock)(void);

@interface TapBlockView : UIView
{
   TapBlock tapBlock;
}

@property (nonatomic, copy) TapBlock tapBlock;
@end

@implementation TapBlockView
@synthesize tapBlock;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
   tapBlock();
}

- (void)dealloc
{
   [tapBlock release];
   [super dealloc];
}

@end

This is a very convenient way of setting up delegate style behavior without having to litter your code with lots of protocol definitions. Now an example of using the view in a view controller:

- (void)viewDidLoad
{
    [super viewDidLoad];
    tapBlockView = [[TapBlockView alloc] initWithFrame:CGRectZero];
    [tapBlockView setTapBlock:^(void) {
        self.someLabel.text = @"You tapped it!";
    }];
}

Everything seems fine right? Nice and convenient.

Not so fast.

Blocks automatically scope capture and retain any object types you use in the block. In this case that variable is “self”. Now we have a retain cycle since self owns the tap view which owns the block which now owns self.

According to Mike Ash, the correct way to handle this is to use a weak pointer (assign) in the block like this:

- (void)viewDidLoad
{
    [super viewDidLoad];
    tapBlockView = [[TapBlockView alloc] initWithFrame:CGRectZero];
    __block typeof (self) weakself = self;
    [tapBlockView setTapBlock:^(void) {
        weakself.someLabel.text = @"You tapped it!";
    }];
}

By using a weak, nonretained pointer along with the __block modifier we’ve broken the retain cycle. For ARC code you should use __weak instead of __block.

There’s two important lessons to be pulled from this. The first is that you always have to be aware of the code you’re writing and look for subtle retain cycles like this one. No amount of automatic reference counting magic can help you in some of these scenarios. The second is that it’s always good to look at code written by others on your team because there’s nearly always something new to learn to refresh on, even if you’re one of the more seasoned developers and the code you’re reading is from a junior dev.

For more information check out these two articles on Mike Ash’s Friday Q&A Site:
9/30/2011 – Automatic Reference Counting
4/30/2010 – Dealing With Retain Cycles

Do Just About Anything With Blocks

I love using blocks in objective-C (and C for that matter).  I think they’re the most useful additions to language since . . . well I don’t know.  I allows your code to be more compact and more logically grouped (remember UIView animation delegates? yeesh).  In some cases, even faster by backgrounding certain operations with GCD.   Sadly, blocks have only made it into a small portion on the SDKs and frameworks, most notably collection enumeration and the vastly improved UIView animations.  Fortunately there’s some enterprising individuals and groups who’ve created some very good libraries for extending blocks to other parts of the framework.

BlocksKit

BlocksKit is an open source library that allows you to do just about anything with blocks.  You can easily apply blocks as selectors to UIControls, UIGestureRecognizers, and NSTimers.  There are facilities to apply blocks in different ways to collections, and through the use of dynamic delegates you can use blocks in place of delegates on alerts and action sheets.  As a bonus there’s some handy utilities for dealing with associated objects too.

Block based drawing

I’ve shared this before,but David Hamrick posted a great demo on using blocks to handle drawing on UIViews without the need to subclass.  Find it here.

UIAlertView+Blocks:

If you don’t need everything in BlocksKit, you can check out UIAlertView+Blocks which works very nicely for working with alerts and actions sheets without the need for a delegate at all.

Note: BlocksKit and the above categories don’t play nice together.  You’ll need to pick on or the other to avoid some very odd runtime bugs.

Some block tips of my own:

Static comparators

Apple added block based comparisons for sorting NSArrays.  The block takes 2 objects and returns an NSComparisonResult.  If you find yourself sorting the same thing in multiple places it’s often faster to statically declare your comparator that you can reuse.  Let’s say we have an array of a custom class person, with strings for first and last name:


@interface Person : NSObject
@property (nonatomic, copy) NSString *firstName, *lastName;
@end

Sorting using a block is simple enough, given an array of Person objects:


[people sortUsingComparator:^NSComparisonResult(id p1, id p2) {
if ([[p1 lastName] isEqualToString:[p2 lastName]])
{
return [[p1 firstName] caseInsensitiveCompare:[p2 firstName]];
}
return [[p1 lastName] caseInsensitiveCompare:[p2 lastName]];
}];

If we want to reuse the comparator multiple places, we store it into a static variable:


static NSComparator personCompare = ^NSComparisonResult(id p1, id p2) {
if ([[p1 lastName] isEqualToString:[p2 lastName]])
{
return [[p1 firstName] caseInsensitiveCompare:[p2 firstName]];
}
return [[p1 lastName] caseInsensitiveCompare:[p2 lastName]];
};

// ...

[people sortUsingComparator:personCompare];

You can do the same thing with literally any block you want to reuse, but you don’t get the benefit capturing scoped variables.

Blocks in forms:

It’s common to have forms made of table cells with text fields for entering user data.  Normally to properly apply the captured data you either have to do some creative work with UIView tags or extend the UITableViewDelegate to hand your new cell type.  You can also use blocks to handle the callback by either adding a block variable to a custom table cell.


typedef void(^TextViewEndCallback)(NSString *enteredText);

@interface MultiLineTextFieldCell : UITableViewCell <UITextViewDelegate>
{
UITextView *textView;
SBTextViewEndCallback textViewEndCallback;
}
@property (nonatomic, retain) IBOutlet UITextView *textView;
- (void)setTextViewEndCallback:(TextViewEndCallback)callback;
@end

The above example uses a text view in a table cell.  The table cell should be delegate for the text view.  In the text view delegate method you need only call the block passed into the cell:


- (void)textViewDidEndEditing:(UITextView *)textView_
{
textViewEndCallback(textView.text);
}

This is very easy to use in your cellForRowAtIndexPath method:


__block SomeClass *object = [objects objectAtIndex:indexPath.row];

[cell setTextViewEndCallback:^(NSString *enteredText) {
object.somestring = enteredText;
}];

We used very similar ideas to the above in SalesBag to speed development along.

That’s it!

I enjoy how blocks can speed development along and allows you to write more flexible and sometimes even more reusable code.  Have any cool block tricks?  I’d love to hear them.  Happy Coding!

Objective-C Quickie – Block variables

Blocks are becoming more and more preferred in iOS and Objective-c, with most of the UIView animations becoming block based and methods added to the NS collection classes to use blocks for enumeration. Blocks can also be stored as variables and used over and over again. This is immensely useful when subscribing to a DRY method of coding.

Below is some code I’m using to apply transformations to CALayers. I’ve got three sets of them, and since I simply want to apply the same transformation to them, I can write the block for creating and applying the transformation once, and use it on all three sets:

// this is a block variable
id transBlock = ^(id obj, BOOL *stop)
{
    CALayer *layer = (CALayer *)obj;
    CGAffineTransform trans = CGAffineTransformConcat([layer affineTransform],                                                       CGAffineTransformMakeTranslation(delta * 0.7, 0));
    [layer setAffineTransform:trans];
};

[displayedBars enumerateObjectsUsingBlock:transBlock];
[displayedBarLabels enumerateObjectsUsingBlock:transBlock];
[displayedAxisLabels enumerateObjectsUsingBlock:transBlock];