5

I wrote the following sample code to see how ARC works

@property (nonatomic, weak) NSString *myString;
@property (nonatomic, weak) NSObject *myObj;
@end

@implementation ViewController
@synthesize myString = _myString;
@synthesize myObj = _myObj;
- (void) viewDidAppear:(BOOL)animated
{
    NSLog(@"Appearing Obj: !%@!",self.myObj);
    NSLog(@"Appearing String: !%@!",self.myString);
}

- (void)viewDidLoad
{
    self.myObj = [[NSObject alloc] init];
    self.myString = [[NSString alloc] init];
    NSLog(@"Loading Obj %@",self.myObj);
    NSLog(@"Loading String: !%@!",self.myString);
}

However surprisingly I got these results:

2012-06-19 15:08:22.516 TESTER[4041:f803] Loading Obj (null)
2012-06-19 15:08:22.517 TESTER[4041:f803] Loading String: !!
2012-06-19 15:08:22.533 TESTER[4041:f803] Appearing Obj: !(null)!
2012-06-19 15:08:22.535 TESTER[4041:f803] Appearing String: !!

As you can see, Obj got released properly but my string (which is also a weak property) does not print out null...Why not?

Brad Larson
  • 170,088
  • 45
  • 397
  • 571
Nosrettap
  • 10,940
  • 23
  • 85
  • 140

2 Answers2

12

NSString uses all sorts of internal trickery to reuse objects and avoid unnecessary allocations and copies. It can do this because NSString instances are immutable. In this case there is probably a shared instance to represent an empty string which is being returned by [[NSString alloc] init], and this shared instance will be retained somewhere else as a singleton.

Mike Weller
  • 45,401
  • 15
  • 131
  • 151
  • That seems to make sense. Thanks! – Nosrettap Jun 19 '12 at 20:14
  • Perhaps somebody can check out the NSString source code to confirm this. – Mike Weller Jun 19 '12 at 20:15
  • Makes sense, though I wouldn't think it would be wise to rely on this behavior, which seems to just be a manifestation of some optimization, which is subject to change at some future date. – Rob Jun 19 '12 at 20:24
  • 3
    One of those optimization are that string literals get exist throughout the lifetime of the application. Also, creating a new string with a reference to a string literal (`[NSString stringWithFormat:@"Hello world"];` or `[[NSString alloc] initWithFormat:@"Hello world"];`) will return a reference to the exact same string literal (like I mentioned in [my answer](http://stackoverflow.com/a/11108549/608157)) – David Rönnqvist Jun 19 '12 at 20:41
  • I guess copy will also yield the same shared instance when you call it on a literal string? – Nicolas Miari Jun 21 '12 at 07:19
  • Yes, copy on an immutably string will just return the same instance with a +1 retain count. But like Robert says, you should not rely on this behaviour. – Mike Weller Jun 21 '12 at 07:20
6

[[NSString alloc] init] always returns identical value. You can check it by yourself.

NSString *string1 = [[NSString alloc] init];
NSString *string2 = [[NSString alloc] init];
NSString *string3 = [[NSString alloc] init];
NSLog(@"string1 = %p, string2 = %p, string3 = %p", string1, string2, string3)

This code returns three identical addresses. In my case, output was:

string1 = 0x3e8dd74c, string2 = 0x3e8dd74c, string3 = 0x3e8dd74c

That means [[NSString alloc] init] returns Singleton. Singletons usually can't be released.

Making strings with other methods (like initWithFormat:) makes usual 'non-singleton' objects, which usually can be released, with some exceptions.

Further: Looking source code (Assembler):

-[NSPlaceholderString init]:
00040ea4        f64b009c        movw    r0, 0xb89c
00040ea8        f2c00016        movt    r0, 0x16
00040eac            4478        add     r0, pc
00040eae            4770        bx      lr

it would be something like this (in objectiveC)

-(id)init
{
    return SOME_CONSTANT_VALUE;
}

It might be kCFEmptyString, but I'm not sure.

Oleg Trakhman
  • 2,082
  • 1
  • 17
  • 35