Commitment Issues
ARC is one of most amazing advances in the history of Objective-C; really in the history of compiler technologies in general.
It’s really cool.
But….
We can’t all just make the jump right this second. No matter how good the ARC migration tool is, there’s a lot of code floating around and the time to migrate and retest can be insurmountable. An intermediary solution would be writing code that works equally well in ARC and non ARC projects.
Enter macros
LLVM, the thing that makes ARC possible, offers some very useful ways to probe for the availablility of features, most notably __has_feature()
. We can test for ARC using objc_arc
and weak using objc_arc_weak
__has_feature(objc_arc)
__has_feature(objc_arc_weak)
These macros expand into 0 or 1 based on the features being turned on at compile time. From there we can build a couple more useful macros to make writing ARC code easier.
HASARC
- Shorthand version of__has_feature(objc_arc)
HASWEAK
- Shorthand version of__has_feature(objc_arc_weak)
-
STRONG
- Expands tostrong
for ARC andretain
for non ARC (useful for property declarations) __STRONG
- Expands to__strong
for ARC and to nothing for non ARC (useful for variable declarations)WEAK
- Expands toweak
for ARC,assign
for non ARC andunsafe_unretained
for ARC without weak support (useful for property declarations)__WEAK
- Expands to__weak
for ARC, to nothing for non ARC environments and to__unsafe_unretained
for ARC without weak support (useful for variable declarations)IF_ARC(ARCBlock, NOARCBlock)
- Function style macro for larger blocks of code that are different in ARCNO_ARC(NoARCBlock)
- Function style macro for code that only executes when ARC isn’t availableNO_WEAK(NoWeakBlock)
- Function style macro for code that only executes when ARC isn’t available or doesn’t support weak (iOS 4, OS X 10.6)
Example
@interface Foo : NSObject
@property (WEAK, nonatomic) id delegate;
@property (STRONG, nonatomic) id observer;
@end
@implementation
@synthesize delegate=_delegate;
@synthesize observer=_observer;
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:_observer];
NO_ARC(
[_observer release];
[super dealloc];
)
}
- (id)init
{
self = [super init];
if (self)
{
// __block was a weak reference pre ARC, but is now a
__WEAK __block __typeof__(self) bSelf = self;
self.observer =
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillDoSomething object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
NSLog(@"This is me: %@", bSelf);
}];
}
return self;
}
@end
@interface Bar : NSObject
@property (STRONG, nonatomic) Foo *foo;
@end
@implementation Bar
@synthesize foo=_foo;
- (void)dealloc
{
NO_WEAK(
_foo.delegate = nil;
)
NO_ARC(
[_foo release];
[super dealloc];
)
}
- (id)init
{
self = [super init];
if (self)
{
_foo = [Foo new];
_foo.delegate = self;
}
return self;
}
@end
It’s available for download on my Github.
Use and enjoy and provide feedback.
FMDB covers very similar ground using a set of macros that wrap retain/release/autorelease.