Alex Rivera | Logout

Objective C - ARC - When to use @autoreleasepool

Asked 2012-02-11T22:48:35.977
11

I was reading a little about ARC and I saw this:

@interface Address : NSObject {
    @public
    NSString *city;
}
@end

@implementation Address
- (Address*) init: (NSString*) c {
    city = c;

    return self;
}

- (void) dealloc {
    NSLog(@"Destroying address: %@", city);
}
@end

@interface Customer : NSObject {
    NSString *name;
    Address *addr;
}
@end

@implementation Customer
- (Customer*) init: (NSString*) n withAddress: (Address*) a {
    //Note 1: Automatic retain on assignment
    name = n;
    addr = a;

    return self;
}

- (void) dealloc {
    NSLog(@"Destroying: %@", name);
    //Note 2: Automatic release of member variables
}

@end

Customer* objectReturnTest() {
    NSString * n = [[NSString alloc] initWithString: @"Billy Bob"];
    Address * a = [[Address alloc] init: @"New York City"];      

    Customer *c = [[Customer alloc] init: n withAddress: a];

    //Note 3: ARC will put the returned object in autorelease pool.
    return c;
}

A couple of basic things to note here. As "Note 1"  says, when an object is assigned to a variable, a call to retain is made automatically. This increments the reference count. As "Note 2" says, when an object is destroyed, all member variable objects are released for you. You no longer have to do that from the dealloc method.

Finally, when a method returns a newly created object, ARC will put the returned object in an autorelease pool. This is stated in "Note 3".

Now, let’s use the code.

int main (int argc, const char * argv[])
{
    NSString * n = [[NSString alloc] initWithString: @"Johnny Walker"];
    Address * a = [[Address alloc] init: @"Miami"];
    Customer *c = [[Customer alloc] init: n withAddress: a];

    NSLog(@"Before force release");
    c = nil; //Force a release
    NSLog(@"After force release");

    @autoreleasepool {

        Customer *c2 = objectReturnTest();

    }
    NSLog(@"After autorelease pool block.");

    return 0;
}

The log output from this code will be:
Edit
Report

1 Answer

15

by line

c = nil; //Forces a release

a Customer instance is deallocated because no one is retaining it, so as a result the output is

Destroying: Johnny Walker

but n and a have not been deallocated because they still remain in the scope and nil has not been assigned to them.

and I don't think this is any kind of memory leak


you normally do not need to use @autorelasepool unless you are doing something like this

- (void)myMethod {
    for (int i = 0; i < 1000000; i++) {
        NSString *string = [NSString stringWithFormat:@"%d", i];
        // do something with string
    }
}

Than 1000000 NSString will be allocated during loop. They will be deallocated after the method returned (actually after this runloop) but already consume too much memory. Therefore should replace to

- (void)myMethod {
    for (int i = 0; i < 1000000; i++) {
        @autoreleasepool {
            NSString *string = [NSString stringWithFormat:@"%d", i];
            // do something with string
        }
    }
}

you should read this to learn more about memory management https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html#//apple_ref/doc/uid/20000047-CJBFBEDI

answered 2012-02-12T03:58:05.493

Your Answer