GC->ARC: From Garbage Collection to Automatic Reference Counting

I just transitioned PhotoLinker and its dependent frameworks from garbage collection (GC) to automatic reference counting (ARC). For the most part this transition went fairly smoothly—I actually had an ARC converted version running in a few days. However, the transition also exposed some poor design patterns (or lack of design patterns one might argue) and ultimately prompted me to do a fairly extensive code refactoring, but I won’t dwell on that here.

The transitioning to ARC release notes are fairly sparse, but do provide most the basic pieces necessary to proceed. ARC and GC use the same basic conceptual rules for memory management: object ownership, strong and weak pointers. With retain and release out the way, this means you use the exact same code for ARC and GC when you’re dealing with pure Objective-C, however, anything outside those bounds and it gets more complicated.

The basic idea is that there are two types of pointers to objects: strong and weak. One or more strong pointers prevent an object from getting deallocated, whereas weak pointers simply point the object and turn to zero if/when the object gets deallocated. The only difference between ARC and GC is that in GC two objects with strong pointers to each other, but no other references, will get deallocated, whereas in ARC this is a retain cycle. So, while you’re coding, just keep in mind which objects have strong pointers to them.

Strong and weak pointers get declared like this in a class definition,

@property(readwrite, strong, nonatomic) NSObject *anObject;

@property(readwrite, weak, nonatomic) NSObject *anObject;

Because the memory management patterns of ARC and GC are nearly identical, there really wasn’t much code transitioning, with one exception: C code. The largest amount of work went into transitioning my primitive C code data chunks that were allocated with NSAllocateCollectable and then freely passed around with weak or strong pointers. Really, it was quite beautiful with GC. I was able to create C structures that contained strong and weak pointers to memory and pass the pointers around freely, while using the same rules that apply to Objective-C objects. Transitioning to ARC meant that I had to do everything in terms of mallocs and frees, and/or wrap things with NSData objects. That was a real pain to transition and, as with anything in C, I ended up with some nasty buffer overflow errors that caused all kinds of trouble.

 

From a developer’s perspective there’s no question that GC was nicer to program with than ARC. Not having retain cycles was great, though not critical. Passing around chunks of malloced memory with the same strong and weak pointer rules was fabulous, and I’m really going to miss that. On the other hand, the coding differences are small and the runtime differences are huge. PhotoLinker with GC on 10.6 was okay, but running PhotoLinker with GC on 10.7 was like getting in a car with a drunk driver: odds are you were going to crash.

I wish I had taken better notes, but here are a few tidbits on transitioning that may be helpful.

– If you want Core Foundation object can be treated as a Cocoa object by using,

@property(atomic, strong) __attribute__((NSObject)) CGLayerRef theLayer;

– When NSMapTable deallocates, it does not cleanup after itself. This means you need to call -removeAllObjects.

 

– When using -beginSheetModalForWindow:ModalDelegate:didEndSelector:contextInfo:, the last argument takes a (void *). Right now I’m casting this as  (__bridge_retained void *) and then getting it as (__bridge_transfer NSArray *) in the alertDidEnd:.

– When implementing -copyWithZone. The first (highest) class needs to call [[self class] alloc] init].