1

I have been trying to understand the difference between Strong and Weak references in iOS. What I did to understand is:

//.h File

@property(nonatomic,strong) NSString* myStrongString;
@property(nonatomic,weak) NSString* myWeakString;


//.m File

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self assignTempString];
    // Do any additional setup after loading the view, typically from a nib.
}


-(void)assignTempString{

    self.myStrongString = [[NSString alloc] initWithString:@"Varun Mehta"];
}

- (IBAction)printAssignedString:(id)sender {

    NSLog(@"Object will have strong reference so it will print my name==%@",self.myStrongString);   
}

According to my understanding when I repeat the above step by using myWeakString it should print null. But its still printing my name. Anybody having any idea why its happening.

But when I replace [[NSString alloc] initWithString:@"Varun Mehta"] with [NSString stringWithFormat:@"Varun Mehta"] or [[NSString alloc] initWithFormat:@"Varun Mehta"] result is coming as I have expected.

Robert
  • 10,403
  • 14
  • 67
  • 117
Varun Mehta
  • 1,733
  • 3
  • 18
  • 39
  • Do you use ARC or MRC? – Avt Apr 11 '14 at 08:13
  • [[NSString alloc] initWithString:@"Varun Mehta"]; is not what it seems to be ... it is not a normal object but a string literal and that is stored differently – Volker Apr 11 '14 at 08:14
  • possible duplicate of [Differences between strong and weak in objective-c](http://stackoverflow.com/questions/11013587/differences-between-strong-and-weak-in-objective-c) – Gabriel.Massana Apr 11 '14 at 08:16
  • hi Avt, I am using ARC – Varun Mehta Apr 11 '14 at 08:16
  • Try just `self.myString = @"Varun Mehta";` just to see what that does. – Fogmeister Apr 11 '14 at 08:39
  • Unluckily you picked a literal string to use to test the behaviour. Literal strings (@"someText") have very high reference counts, making it impossible to get deallocated, this is an optimisation that the system does. Try the same thing using an NSArray, and you will see that it will get deallocated with the weak property, you will even get a compiler warning as you make the assignment! – Kaan Dedeoglu Apr 11 '14 at 09:40

5 Answers5

2

There are several things to consider here.

  1. A statically declared string is built into your app so it isn't really retained or released, thus a weak reference to @"my string" will always be valid. The compiler is just recognizing [[NSString alloc] initWithString:@"Varun Mehta"] as a static string and removing your alloc/init. However anything that deals with formatting is, by definition, creating a new string and thus the new string obeys the weak referencing rules and is immediately deallocated, nil-ing out the reference.

  2. If you access a weakly retained object that ends up in the autorelease pool it won't actually get deallocated until all your methods return and the run loop goes back into another cycle (and thus drains the autorelease pool), so you can continue to work with the object even though it is "walking dead". This is typically only when interacting with non-ARC code.

russbishop
  • 16,587
  • 7
  • 61
  • 74
1

If you need practise try this code:

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self assignTempString];
}


-(void)assignTempString{

    @autoreleasepool
    {
        self.myStrongString = [NSString stringWithFormat:@"%@", @"Strong string"];
        self.myWeakString = [NSString stringWithFormat:@"%@", @"Weak string"];
    }

}

- (IBAction)printAssignedString:(id)sender {

    NSLog(@"Strong ptr content: %@",self.myStrongString);
    NSLog(@"Weak ptr content: %@",self.myWeakString);
}
Cy-4AH
  • 4,370
  • 2
  • 15
  • 22
  • Open Xcode, paste your code and run it. Exact same behaviour as in the question. The autorelease pool does not change the behaviour in any way. -> not useful – Matthias Bauch Apr 11 '14 at 09:28
  • @MatthiasBauch, Ah! `stringWithString` have fooled me. I have edited code. – Cy-4AH Apr 11 '14 at 09:38
0

[NSString alloc] will allocate an ARC-managed object and will set its retain count to 1. As long as your view controller is alive, this retain count will be 1, so it will not be deallocated. [NSString stringWithFormat:] returns an autoreleased string which is deallocated after the execution of [self assignTempString].

Vame
  • 2,033
  • 2
  • 18
  • 29
0

Two methods initWithString and stringWithFormat suggest exactly what is to expect. So initWithString expects you to create allocate memory and then initialise it. While stringWithFormat expects you to just point to the string.

When you do a init with your strong/weak variable it will exist till end of your program. While when you point; strong literal will keep a reference and hence will not allow ARC to cleanup the string literal, weak literal will not keep a reference and hence ARC is free to clean it up immediately after the function call.

Hope it clarifies working for you.

katch
  • 820
  • 1
  • 7
  • 24
0

What you are experiencing happens because of how NSString is implemented.

Since NSString objects are immutable the compiler takes a shortcut when you use stringWithString: with a string literal as argument. If the argument of this and other related methods is a string literal the returned value will just point to the string literal. The whole object instantiation is optimized away.

And string literals won't be deallocated. But the weak variable is only nil'd out during dealloc, so if dealloc is never called the weak variables are never set to nil.

This won't happen if you use stringWithFormat:. Even using only string literals as argument will create new string instances.
Why? Most likely because Apple decided that it's not worth the effort to check if stringWithFormat: was used with a string literal that does not have any format specifiers.

That's an implementation detail, don't think too long about this decision. It should not influence the code you write. I would suggest you treat every string that is not a bare literal (i.e. @"Foo" without any NSString methods) as dynamically created NSString (i.e. use isEqualToString: for all your string comparisons)


This logging code will show this reuse behaviour. It'll show the same addresses for all NSString instances, because the compiler has optimized all those calls to a simple @"Foo".

NSLog(@"%p", @"Foo");
NSLog(@"%p", [[NSString alloc] initWithString:@"Foo"]);
NSLog(@"%p", [NSString stringWithString:@"Foo"]);
NSLog(@"%p", [[NSString stringWithString:@"Foo"] copy]);
NSLog(@"%p", [@"Foo" copy]);

In newer versions of Xcode you will even get nice warnings for this code:

using initWithString: with a literal is redundant
using stringWithString: with a literal is redundant

Matthias Bauch
  • 89,811
  • 20
  • 225
  • 247