Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ObjectiveC: Strange behavior when using NSString and __weak with ARC

First code and output:

NSString *text = @"Sunny";
__weak NSString *string0 = text.lowercaseString;
__weak NSString *string1;
string1 = text.lowercaseString;

NSLog(@"%@, %@", string0, string1);

Output:

(null), sunny

But after I move the declaration of string1 above the text, output is different. Here is the code:

__weak NSString *string1;
NSString *text = @"Sunny";
__weak NSString *string0 = text.lowercaseString;
string1 = text.lowercaseString;

NSLog(@"%@, %@", string0, string1);

Output:

sunny, sunny

I am very confused with the different output:

  • Why string0 and string1 is different in the first case?
  • Why the output of second case is different with the first?
like image 258
webfrogs Avatar asked Jul 21 '15 03:07

webfrogs


1 Answers

Trying to figure out exactly when an object is released or a weak reference nulled can be challenging, and often doesn't really help understanding. Here are some reasons why you can see different results than you expect:

  • NSString: It is best never to use this type when doing these kind of investigations. String literals are immortal, they are not collected, and you may have a string literal even when you don't expect one.
  • The auto-release pool: The auto-release pool is really a hangover from the pre-ARC days, but it still exists and many methods return auto-released objects. What this means is many objects will live longer than you might expect, but not too long. However ARC has tricks and can remove objects from the auto-release pool early, so you might first think the object will live longer and then it doesn't...
  • weak references: After the first two bullets you should guess that as you might have no real idea when an object gets released, if at all, then you might have no real idea when a weak reference gets nulled. Just think "soon enough".
  • Optimisation: There is some leeway in optimisations the compiler can do which, while retaining the correct semantics of your program, may alter the lifetime of objects.

If you do want to run these kind of investigations then you will probably get further if (a) use your own class types, not anything from the libraries and (b) use @autoreleasepool { ... } blocks to limit the lifetimes of auto-released objects.

As an example, when I ran your code on the compiler I was using I did not get a (null), however changing the first assignment to string0 = text.lowercaseString.mutableCopy did produce one... Figuring out why is left as an exercise...

Have an inquiring mind and explore, that is good, but be prepared for the non-obvious!

HTH

like image 154
CRD Avatar answered Oct 16 '22 23:10

CRD