I am a little bit stubborn, but I want to understand weak and strong references well, so that's why I'm asking you once again.
Consider this:
__weak NSString* mySecondPointer = myText; NSLog(@"myText: %@", myText);
The result is myText: (null)
and it is pretty obvious - weak reference is set to null just after assignment, cause there is no strong reference to the pointed object.
But in this case:
__strong NSString* strongPtr = [[NSString alloc] initWithFormat:@"mYTeSTteXt %d"]; // weak pointer points to the same object as strongPtr __weak NSString* weakPtr = strongPtr; if(strongPtr == weakPtr) NSLog(@"They are pointing to the same obj"); NSLog(@"StrongPtr: %@", strongPtr); NSLog(@"weakPtr: %@", weakPtr); NSLog(@"Setting myText to different obj or nil"); // after line below, there is no strong referecene to the created object: strongPtr = [[NSString alloc] initWithString:@"abc"]; // or myText=nil; if(strongPtr == weakPtr) NSLog(@"Are the same"); else NSLog(@"Are NOT the same"); NSLog(@"StrongPtr: %@", strongPtr); // Why weak pointer does not point to nul NSLog(@"weakPtr: %@", weakPtr);
The output:
2013-03-07 09:20:24.141 XMLTest[20048:207] They are pointing to the same obj 2013-03-07 09:20:24.142 XMLTest[20048:207] StrongPtr: mYTeSTteXt 3 2013-03-07 09:20:24.142 XMLTest[20048:207] weakPtr: mYTeSTteXt 3 2013-03-07 09:20:24.143 XMLTest[20048:207] Setting myText to different obj or nil 2013-03-07 09:20:24.143 XMLTest[20048:207] Are NOT the same 2013-03-07 09:20:24.144 XMLTest[20048:207] StrongPtr: abc 2013-03-07 09:20:24.144 XMLTest[20048:207] weakPtr: mYTeSTteXt 3 // <== ??
My question:
Why after strongPtr = [[NSString alloc] initWithString:@"abc"];
weak pointer value is not changed to nil (why the object created at the beginning still exists in memory, despite it does not have any strong refs? -- or maybe it has?)
I have tried that one: (but it is not good for adding a comment I suppose). I have included the code where I am creating a strongPtr in @autorealesepool. I not sure if it is correct solution but it work...
__strong NSString* strongPtr; __weak NSString* weakPtr; @autoreleasepool { strongPtr = [[NSString alloc] initWithFormat:@"mYTeSTteXt %d", 3]; // weak pointer point to object create above (there is still strong ref to this obj) weakPtr = strongPtr; if(strongPtr == weakPtr) NSLog(@"They are pointing to the same obj"); NSLog(@"StrongPtr: %@", strongPtr); NSLog(@"weakPtr: %@", weakPtr); NSLog(@"Setting myText to different obj or nil"); // after line below, there is no strong referecene to the created object: strongPtr = [[NSString alloc] initWithString:@"abc"]; } if(strongPtr == weakPtr) NSLog(@"Are the same"); else NSLog(@"Are NOT the same"); NSLog(@"StrongPtr: %@", strongPtr); // Why weak pointer does not point to nul NSLog(@"weakPtr: %@", weakPtr);
Output:
2013-03-07 09:58:14.601 XMLTest[20237:207] They are pointing to the same obj 2013-03-07 09:58:14.605 XMLTest[20237:207] StrongPtr: mYTeSTteXt 3 2013-03-07 09:58:14.605 XMLTest[20237:207] weakPtr: mYTeSTteXt 3 2013-03-07 09:58:14.606 XMLTest[20237:207] Setting myText to different obj or nil 2013-03-07 09:58:14.607 XMLTest[20237:207] Are NOT the same 2013-03-07 09:58:14.607 XMLTest[20237:207] StrongPtr: abc 2013-03-07 09:58:14.608 XMLTest[20237:207] weakPtr: (null)
strong is the default. An object remains “alive” as long as there is a strong pointer to it. weak specifies a reference that does not keep the referenced object alive. A weak reference is set to nil when there are no strong references to the object.
A weak reference allows the garbage collector to collect an object while still allowing an application to access the object. If you need the object, you can still obtain a strong reference to it and prevent it from being collected.
strong reference (plural strong references) (computing) a reference that does protect the referenced object from collection by a garbage collector.
From the assembly code it can be seen that accessing weakPtr
generates a objc_loadWeak
call.
According to the Clang documentation, objc_loadWeak
retains and autoreleases the object and is equivalent to
id objc_loadWeak(id *object) { return objc_autorelease(objc_loadWeakRetained(object)); }
This (hopefully) explains why both
if(strongPtr == weakPtr) ...
and
NSLog(@"weakPtr: %@", weakPtr);
create additional autoreleased references.
This is not a special NSString
problem, I could reproduce the same behaviour with a custom (plain) class.
First, don’t experiment with weak references or other memory management behaviour on NSString
, there’s too much magic in that class. Not that weak references wouldn’t work with NSString
, just the behaviour is slightly trickier than you would expect and easily leads to incorrect conclusions. See these previous questions:
When you wrap your code example with an autorelease pool and log the weak string pointer afterwards, it’s nil
indeed. It might even be the case that you would get similar behaviour with classes other than NSString
– you are simply not guaranteed that the weak references will be cleared at the precise moment you lose the last strong reference to an object. Or maybe you are, but it’s hard to tell when exactly the last strong reference disappears because of the autorelease pools in play, as hinted to by this example (and nicely explained by Martin’s answer).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With