ARC and copy

Like many of you, I’ve recently starting coming to terms with automatic reference counting (ARC) in Objective-C. For the most part, it’s gone remarkably smoothly. The only hard part is remembering to not type autorelease!

ARC lets us get rid of the retain/release pairs in our code. But can you spot the bug in the following code?

@interface MyObject : NSObject

@property (copy) id ivar;

@end


@implementation MyObject

@synthesize ivar = _ivar;

- (id)initWithIvar:(id)ivar
{
  self = [super init];
  if (self != nil) {
    _ivar = ivar;
  }
  return self;
}

@end

The ivar instance variable is a strong reference, not a copy. Since I think it’s a bad idea to use accessors during -init the copy semantics defined by the @property are never used and ARC happily retains the reference instead of copying it. Also of note: the static analyzer doesn’t think there’s anything wrong with the code above, so you won’t see any warnings that you’ve screwed up.

In my case, this initializer led to a bug where several worker threads were modifying the same instance variable and, well, you know how that goes. The fix, as usual, was painfully simple:

    _ivar = [ivar copy];

It’s important to remember that ARC primarily affects how we use -retain and -release. As Matt Drance points out the way -copy works hasn’t changed significantly. Just because we can forget about typing “retain” and “release”, doesn’t necessarily mean that we can forget to type “copy”, too.

Updated May 4th, 2012: A Radar about the static analyzer not issuing a warning has been filed: rdar://11386493