Tropical Software Observations

06 September 2012

Posted by Anonymous

at 9:07 AM

0 comments

Labels: , ,

Breaking ARC Retain Cycle in Objective-C Blocks

In a recent client project, we noticed its iOS app often received low memory warnings. The iOS app is developed with ARC-enabled (Automatic Reference Counting).
When profiling the app using Instruments > Allocations, we found that a lot of unused ViewController objects were not being released from memory.

Retain Cycle

The codebase uses a lot of Objective-C blocks as shown below, and self is often being called within the blocks:




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@interface DetailPageViewController : UIViewController
@property(nonatomic, strong) UIButton *backButton;
...
@end

@implementation DetailPageViewController
@synthesize backButton;

- (void)loadView {
  ...
  [self.doneButton onTouch:^(id sender) {
    [self doSomething];
    self.isDone = YES;
  }];
}
...
@end

In this example code, the controller object holds a strong reference to a doneButton object. But because the doneButton onTouch: block is referencing self, now the button object holds a strong reference back to the controller object.
When object A points strongly to object B, and B points strongly to A, a retain cycle is created, and both objects cannot be released from memory.

Use Lifetime Qualifiers

Apple Developer’s guide on ARC transition suggested a few ways to break the retain cycle using different lifetime qualifiers. It is definitely a must read for iOS development.
If your app is targeted for iOS 5, you can use the __weak lifetime qualifier to break the cycle:




1
2
3
4
5
6
7
8
9
10
@interface DetailPageViewController : UIViewController
- (void)loadView {
  ...
  __weak DetailPageViewController *controller = self;
  [self.doneButton onTouch:^(id sender) {
    [controller doSomething];
    controller.isDone = YES;
  }];
}
@end

Because we are using the __weak qualifier here, the doneButton onTouch: block only has a weak reference to the controller object. Now, the controller object will be released from memory when its reference count drops to 0.

0 comments: