What is ARC?

No idea what “Automatic Reference Counting” is or what I should be looking out for in testing it. Can anyone enlighten me?

(Edit: this is probably a better explanation: http://blog.mugunthkumar.com/articles/migrating-your-code-to-objective-c-arc)

Apple introduced ARC technology as part of their Apple LLVM compiler.

Objective-C uses a “reference counting” system to manage memory. (Lua uses “garbage collection” for comparison).

Reference counting simply means that each object instance increases an internal counter each time it is used (“retained”). And decreases each time it is freed (“released”). When the counter reaches zero, it is supposed to mean that your code is no longer using the object anywhere and it can safely be deallocated. The memory can then be re-used for other objects.

So over time Objective-C has developed a coding style entirely around its memory management system. Methods adopt special naming prefixes depending on what they do, memory-wise.

So in classic Objective-C you might have this code:

//Interface
@interface MyObject : NSObject

//A "retain" property implies ownership, 
//  i.e. any object assigned to this property will be retained
@property (nonatomic, retain) NSArray* arrayOfObjects;

- (void) methodOnMyObject:(NSObject*)anotherObject;

@end

//--------------------------
//Implementation

@implementation MyObject

//Generates getter/setter code for this property
@synthesize arrayOfObjects;

- (id) init
{
    self = [super init];
    if( self )
    {
        //Here we alloc a new array (reference count 1), 
        //  assign it to a "retain" property (reference count 2),
        //  add it to the global "autorelease" pool (reference count will be decreased to 1 in 
        //    the next iteration of the run loop — some point in the future)

        self.arrayOfObjects = [[[NSArray alloc] init] autorelease];
    }
    return self;
} 

- (void) dealloc
{
    //Called when reference count for "MyObject" reaches zero

    //Release the array that we own
    //This causes every object inside the array to be "released" once, decrementing its
    // reference count and potentially deallocing
    [arrayOfObjects release];

    //Call superclass dealloc
    [super dealloc];
}

- (void) methodOnMyObject:(NSObject*)anotherObject
{
    //Here we add a new object to our array

    //newObject is alloc'd, reference count is 1
    NSObject *newObject = [[NSObject alloc] init];

    //newObject is added to array, reference count increments to 2
    [arrayOfObjects addObject:newObject];

    //we must release "newObject" balancing out the initial alloc
    [newObject release];

    //We can do stuff with "anotherObject" but we should never "release" it, as 
    // we do not own the object
}

@end

With ARC, the compiler inserts the “retain” and “release” calls for you (and optimises their placement and use). The above code becomes:

//Interface
@interface MyObject : NSObject

//A "strong" property implies ownership
@property (nonatomic, strong) NSArray* arrayOfObjects;

- (void) methodOnMyObject:(NSObject*)anotherObject

@end

//--------------------------
//Implementation

@implementation MyObject

@synthesize arrayOfObjects;

- (id) init
{
    self = [super init];
    if( self )
    {
        //LLVM does semantic analysis here and figures out how to balance the memory
        // it uses our "strong" ownership, and the fact we are allocing to work it out

        self.arrayOfObjects = [[NSArray alloc] init];
    }
    return self;
} 

//No need for a "dealloc" method. LLVM will write it.

- (void) methodOnMyObject:(NSObject*)anotherObject
{
    //Here we add a new object to our array

    //newObject is alloc'd, reference count is 1
    NSObject *newObject = [[NSObject alloc] init];

    //newObject is added to array, reference count increments to 2
    [arrayOfObjects addObject:newObject];

    //LLVM will release "newObject" here

    //We can do stuff with "anotherObject" but we should never "release" it, as 
    // we do not own the object
}

@end

So it formalises the coding style and memory management in Objective-C. It’s an extremely good addition, and I don’t want to code without it anymore (it saves huge amounts of mechanical memory management code from being written).

However migrating a large project, such as Codea, is filled with special cases. Such as “weak” properties, retain cycles, delegates and other memory use-cases that need to be reasoned about in order to apply ARC correctly. Sometimes I need to get involved with the conversion.

Ah. Now I know.

\my brain hurts\

Once again, I’m reminded why I’m not coding in objective C.

It’s not too bad, I like it a lot more than C++.

Anyway, are there any serious issues with the ARC-3 build? Is it fairly stable?

I’d like to submit it to the App Store as the 1.4.4 update if all-is-well.

Nothing I’ve done so far has come up with anything other than the New Project crash. I’ve not been doing anything too intensive, though: modified all my programs to work with a central library and fiddled around with Brickout.

It’s been behaving fine for me, though I’m just refactoring code in the endless project and doing little to test new features.

My problem with objective C is the somewhat obscure syntax and the 80’s style memory management. I got enough of pointers and handles coding for the original Mac in '84. Though it provides fine control, I’d just as soon never malloc again.

@Andrew_Stacey but the ARC-3 build fixes the new project crash, right?

Yes! Sorry for not being clear.

I’m having an issue on the ARC-3 build where the fonts get lost after several code/run cycles. I can give you a screen shot if you like, but the result is that letters are replaced by smears, blocks, and semi-circles. One it happens, selecting a different font doesn’t help. Exiting Codea, shutting it down, then restarting fixes the problem for another dozen or so cycles.

@Mark are you able to recreate this consistently? For example, pressing run 12 times or so?

Nope. It happens pretty consistently, but only after I’ve been coding for a good while. It seems to happen more quickly when I’m bouncing between projects, sipping snippets of code.