Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Objective-C: Weak attritube don't work as expected [duplicate]

Possible Duplicate:
Why do weak NSString properties not get released in iOS?

I'm a newbie to Objective C and I've got some questions that I cannot answer myself. I have a block of code for testing __weak variable (I'm using ARC, of course):

NSString *myString = [[NSString alloc] initWithFormat:@"John"];
NSString * __weak weakString = myString;
myString = nil; //<-- release the NSString object
NSLog(@"string: %@", weakString);

The output of the above codes is as expected, since weakString is a weak variable :

2013-01-02 11:42:27.481 ConsoleApp[836:303] string: (null)

But when I modified the code to this:

NSString *myString = [[NSString alloc] initWithFormat:@"John"];
NSString * __weak weakString = myString;
NSLog(@"Before: %@", weakString); //<--- output to see if the __weak variable really works.
myString = nil;
NSLog(@"After: %@", weakString);

The output is totally not what I expected:

2013-01-02 11:46:03.790 ConsoleApp[863:303] Before: John
2013-01-02 11:46:03.792 ConsoleApp[863:303] After: John

The output of the latter NSLog must have been (nil) instead of "John". I've tried to search in many documents but I haven't found the answer for this case. Can someone give an reasonable explaination? Thanks in advance.

like image 561
hoang Cap Avatar asked Jan 02 '13 04:01

hoang Cap


1 Answers

The NSLog function is retaining the passed NSString in an autorelease pool. The zeroing-weak variable will therefore not be zeroed until the autorelease pool has drained. For example:

__weak NSString* weakString = nil;

@autoreleasepool {
    NSString* myString = [[NSString alloc] initWithFormat:@"Foo"]; // Retain count 1
    weakString = myString;         // Retain count 1
    NSLog(@"A: %@", weakString);   // Retain count 2
    NSLog(@"B: %@", weakString);   // Retain count 3
    myString = nil;                // Retain count 2
    NSLog(@"C: %@", weakString);   // Retain count 3

    NSAssert(weakString != nil, @"weakString is kept alive by the autorelease pool");
} 

// retain count 0
NSAssert(weakString == nil, @"Autorelease pool has drained.");

Why is NSLog putting the string into an autorelease pool? That's an implementation detail.

You can use the debugger or Instruments to follow the retain count of the NSString instance. The exact retain counts are unimportant, but it does shed some light as to what's going on behind the scenes. What is important is that the NSString instance is deallocated when the autorelease pool is drained.

like image 57
Darren Avatar answered Oct 04 '22 18:10

Darren