Jeremy W. Sherman

stay a while, and listen

Retain Still Matters

I recently received a question about this particular bit of code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//cc -Wall -Wextra -Weverything -g -framework Foundation -fobjc-arc \
//nsstring-weak.m -o nsstring-weak
#import <Foundation/Foundation.h>

int
main(void)
{
/* nsstring-weak.m:7:22:
 * warning: assigning retained object to weak variable; object will be released
 * after assignment [-Warc-unsafe-retained-assign] */
    NSString *__weak stringInit = [[NSString alloc] initWithFormat:@"Lewis"];
    NSLog(@"stringInit: %@", stringInit);  // stringInit logs as (null)

    NSString *__weak stringLiteral = @"String";
    NSLog(@"stringLiteral: %@", stringLiteral);

    NSString *__weak stringFormat = [NSString stringWithFormat:@"SomeString"];
    NSLog(@"stringFormat: %@", stringFormat);
}

As the comment points out, clang warns about the first assignment, the one to stringInit, but not to any of the others.

You might read this as, “Assigning to weak blah blah blah released after assignment.” OK, well, now that you point it out clang, duh. I’ll fix that.

But then you look at the other two assignments: Why is clang OK with these?

Here’s the warning again:

nsstring-weak.m:7:22: warning: assigning retained object to weak variable; object will be released after assignment [-Warc-unsafe-retained-assign]

It turns out the real keyword in that message is the one you very well might have glossed over the first time: retained.

That’s the difference between the three object references:

  • stringInit refers to an object returned by alloc–init. This was returned retained, and will be lovingly put to death ASAP by ARC.
  • stringLiteral refers to a string literal. This will outlast even the run of the program; it’s chilling in static memory.
  • stringFormat’s referent was returned by a message parallel to that of stringInit’s, with one difference: the return value is autoreleased, not retained.

So you can still run into differences between objects returned from an alloc–init pair and those returned autoreleased under ARC, even in a bit of wotsit-wotsit code as minimal as this.

If you’d like to learn more, the nearly definitive reference on ARC lives in the Clang docs.

The actually definitive reference, of course, is clang’s source code coupled with the Obj-C runtime code.