ARC for Dummies


#1

Hi guys,
Newbie here! I’m an old telecom programmer (at 36yo lol!), and I’m using your book to jumpstart my career back into the wonderful world of coding! And… I’m loving it!

So I’ve been reading the news and comments on the new ARC compiler code in v5. All I can say is, wow, there ya go. The game has changed. But how much has it changed? Where hasn’t it? Where do I go from here?

Here’s my request: Would you guys be willing to write a short, new ebook with “The new Dos and Don’ts for memory management in iphone 5” that specifically addresses new memory management practices. And perhaps even, an explaination of how the new ARC code works too? It’s mostly “new habits” that I’d like to learn from y’all - the kings of code. Otherwise, I’m sure I’ll pick up some nasty habits, or take some nasty falls trying to relearn the new v5 memory management practices.

Thanks for the great book. It is truly The Guide for me!


#2

Since ARC changes a lot, we’ll be writing a 3rd edition of the book ASAP to address these changes.

In the interim, here is what you need to know:

ARC automatically inserts retain, release and autorelease in your code for you. Most of the time, ARC “just works.” Thus, you setting a variable to point at an object automatically retains that object. Setting a variable to another value if it already points to an object releases the object it previously pointed to.

As an example, setter methods typically look like this:

- (void)setString:(NSString *)str
{
     [str retain];
     [string release];
     string = str;
}

However, with ARC, setter methods look like this:

- (void)setString:(NSString *)str
{
     string = str;
}

And this is okay, old string is released automatically, new str is retained automatically.

Also, methods that return a pointer to an object will automatically autorelease that object:

- (NSString *)gimmeString
{
      return [[NSString alloc] initWithString:@"hey"];
}

The compiler knows that this should be autoreleased.

So, the only thing you typically have to worry about is retain cycles; where two objects have pointers to each other. In this situation, you must figure out which object is the parent and which is the child. The child will only have a weak reference to its parent, so any instance variable or property it has to hold its parents needs to be declared as such.

Weak instance variables are declared like so:

SomeObject __weak *parent;

And weak properties like so:

@property (nonatomic, weak) id parent;

The only thing to get over is the crippling fear of creating objects and not explicitly releasing them. :slight_smile:


#3

The only thing to get over is the crippling fear of creating objects and not explicitly releasing them.

Seriously! lol!! So if I am coding my first apps starting with Xcode 4.2, what strategy do you recommend:

  1. Just code your apps for ios 4 and later. And thus, don’t worry about retain and release anymore.

  2. Backcode to the older ios versions…

Well, speaking of which, do you discuss ios versions and coding to earlier versions in the book? Are my friends with iphone 3 just not gonna get my app at all? Any thoughts on that, especially considering that ios 3 won’t run any apps I build (now that I’m skipping all the retain and release action)?

Thanks!


#4

The upgrade numbers between iOS versions are really high. Moving forward with new features is almost always a good idea.

ARC will work on 4.x devices, as long as you don’t use “weak” references. (You can still use __unsafed_unretained, though.)


#5

Hi Joe,

Since ios5 will be the version of my apps by the time I finish, I’d love to program them with Arc now.
My understanding is there is a tool which could convert your code into Arc-ified version of same.
I am unclear as to how well that tool works.

Is there anyway you could run the tool on your book code, and assuming it works, post it for those who want to
learn with Arc from the get go??

Thank you!


#6

A late reply - Well, you could just read the book and use ARC yourself, simply by ignoring everything the book says about memory management and ignoring all the retain, release, overriding dealloc etc, and let ARC do it for you. It might sound a bit confusing, but i think it will just make it all go smoother ones you get into the habit of doing it. This is just until the new edition comes out of course.

This is just what i am doing, and what another author told me to do with his book. As to the thing about converting your old 4.1 files to 4.2 using ARC, just simply open them, and press “edit -> Refactor -> Objective-C ARC” - Something like that, and then you can convert it to using ARC and Xcode will automatically correct and remove the release, retain messages and so forth.

Hope i helped.
/JBJ

Follow me on - www.jbjprogramming.com


#7

Mr Conway,

Using the Instruments/Profile Leaks tool I seem to get the same results (zero memory leaks) with the following code snippets (specifically the ‘main’ function implementations labeled [color=#BF0000]scenario 1[/color] and [color=#BF0000]scenario 2[/color]) (please note: I am currently in the second chapter of your iOS Programming - 2nd ed):

#import <Foundation/Foundation.h>
#import “Possession.h”

void init(NSMutableArray* items);
void trace(NSMutableArray* items);

void init(NSMutableArray* items)
{
if (nil == items) return;

[items addObject:@"0) Zero"];
[items addObject:@"1) One"];
[items addObject:@"2) Two"];
[items addObject:@"3) Three"];

trace(items);

}

void trace(NSMutableArray* items)
{
if (nil == items) return;
unsigned long itemsCount = items.count;
for (unsigned long i = 0; i < itemsCount; ++i)
{
NSLog(@"%@", [items objectAtIndex:i]);
}
}

[color=#BF0000]Scenario 1:[/color]

int main (int argc, const char * argv[])
{
@autoreleasepool
{
}

NSMutableArray* items = [[NSMutableArray alloc] init];

init(items);

Possession* p = nil;

for (int i = 0; i < 10; ++i)
{
    p = [[Possession alloc] init];
    [p Publish:i];
}

return 0;

}

[color=#BF0000]Seems to the same as Scenario 2:[/color]

int main (int argc, const char * argv[])
{
@autoreleasepool
{
NSMutableArray* items = [[NSMutableArray alloc] init];

    init(items);

    Possession* p = nil;

    for (int i = 0; i < 10; ++i)
    {
        p = [[Possession alloc] init];
        [p Publish:i];
    }
    
}

return 0;

}

Both these ‘main’ functions seem to produce identical results with @autoreleasepool.

Therefore are the contents between the braces not important? Is the compiler using ‘@autoreleasepool’ to hint to the compiler what to do with my source code? I confess I am finding it hard to find a ‘best practice’ on how to leverage this feature. In short should I just declare ‘@autoreleasepool’ in ‘main’ and only be concerned with weak pointers as you noted previously in this forum or should I be placing my code between the braces ‘@autoreleasepool’, and if so why?

Thanks Much,

Bill Berry


#8

The Leaks Instrument won’t be able to pick up leaks in an application that terminates so quickly. Really, you will need an application with an event loop to see if objects stick around longer than they should.


#9

I’m asking for the best way to proceed with the studies in the book for chapter 2, moving forward.
The first block below is from (xCode 4.2) default @autorelease implementation. The second is from the books exercise. They both compile. Which one should I use to complete the book. fyi, I cannot upgrade to Loin yet, thus cannot use ARC (I use Autodesk Maya 3D, which has problems running with 10.7). I need to understand (manual) memory management so I can complete the other book “Objective-C Programming TBNR guide”. Any advice would be appreciated.
// first block

 @autoreleasepool {
      // create a mutable array, store its address in items variable
        NSMutableArray *items = [[NSMutableArray alloc]init];
        
        [items release];
        items = nil;
    }
    return 0;

// second block

 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
      // create a mutable array, store its address in items variable
        NSMutableArray *items = [[NSMutableArray alloc]init];
        
        [items release];
        items = nil;
    
    [pool drain];
    return 0;