在强者消失后,为什么我的弱参考不被清除?

时间:2021-12-27 03:13:25

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.

结果是myText:(null)并且非常明显 - 在赋值之后,弱引用被设置为null,因为没有对指向对象的强引用。

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?)

为什么在strongPtr = [[NSString alloc] initWithString:@“abc”]之后;弱指针值不会改为nil(为什么在开头创建的对象仍然存在于内存中,尽管它没有任何强大的引用? - 或者它可能有?)


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...

我尝试过那个:(但我认为添加评论并不好)。我已经包含了我在@autorealesepool中创建strongPtr的代码。我不确定它是否是正确的解决方案,但它有效...

 __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)

4 个解决方案

#1


17  

From the assembly code it can be seen that accessing weakPtr generates a objc_loadWeak call.

从汇编代码可以看出,访问weakPtr会生成objc_loadWeak调用。

According to the Clang documentation, objc_loadWeak retains and autoreleases the object and is equivalent to

根据Clang文档,objc_loadWeak保留并自动释放对象,相当于

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.

这不是一个特殊的NSString问题,我可以使用自定义(普通)类重现相同的行为。

#2


3  

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:

首先,不要在NSString上试验弱引用或其他内存管理行为,这个类中有太多魔法。并不是弱引用不适用于NSString,只是行为比你想象的稍微复杂,并且很容易导致不正确的结论。看到以前的这些问题:

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).

当您使用自动释放池包装代码示例并在之后记录弱字符串指针时,它确实是零。甚至可能会出现与NSString以外的类相似的行为 - 您无法保证在丢失对对象的最后一个强引用的精确时刻将清除弱引用。或者也许你是,但很难说出最后一个强引用何时消失,因为游戏中的自动释放池,正如这个例子暗示的那样(并且很好地解释了Martin的答案)。

#3


1  

when you do

当你这样做

strongPtr = [[NSString alloc] initWithString:@"abc"]

strongPtr = [[NSString alloc] initWithString:@“abc”]

you strongPtr is pointing to new allocated object, and since the previous object it was pointing too didn't get deallocated, the weak pointer still points to a valid address.

你strongPtr指向新分配的对象,并且因为它指向的前一个对象也没有被释放,所以弱指针仍然指向一个有效的地址。

btw. you can print the memory address off an object with

顺便说一句。你可以用一个对象打印内存地址

NSLog(@"%@", [NSString stringWithFormat:@"%p", theObject])

NSLog(@“%@”,[NSString stringWithFormat:@“%p”,theObject])

#4


1  

Not sure the OP's question and/or the accepted answer here is still valid, at least not as of the results I'm seeing with iOS9/Xcode7.

不确定OP的问题和/或这里接受的答案是否仍然有效,至少不是我在iOS9 / Xcode7中看到的结果。

Here's a (slightly cleaned up) version of the OP's code...

这是OP代码的一个(略微清理)版本......

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
    @autoreleasepool
    {
        NSString* __strong strongPtr = [[NSString alloc] initWithFormat:@"Life, Universe, Everything: %d", 42];
        NSString* __weak   weakPtr   = strongPtr;

        NSLog(strongPtr == weakPtr ? @"Same" : @"Different");
        NSLog(@"  StrongPtr: %@", strongPtr);
        NSLog(@"  weakPtr:   %@", weakPtr);

        NSLog(@"Changing strongPtr to something else...");
        // After this is set, there is no strong reference to the created object
        strongPtr = [[NSString alloc] initWithFormat:@"Drink: %@", @"Pan-galactic Gargle Blaster!"];

        NSLog(strongPtr == weakPtr ? @"Same" : @"Different");
        NSLog(@"  StrongPtr: %@", strongPtr);
        NSLog(@"  weakPtr:   %@", weakPtr);
    }

    return 0;
}

And here's the (truncated) output...

这是(截断的)输出......

Same
  StrongPtr: Life, Universe, Everything: 42
  weakPtr:   Life, Universe, Everything: 42

Changing strongPtr to something else...

Different
  StrongPtr: Drink: Pan-galactic Gargle Blaster!
  weakPtr:   (null)

Program ended with exit code: 0

Here accessing the weak references in the conditionals (as per the accepted answer's explanation) doesn't keep an auto-released reference around as you can see by the (null) in the output.

在这里访问条件中的弱引用(根据接受的答案的解释)不会保留自动释放的引用,如输出中的(null)所示。

...or did I accidentally change the OP's question to the point where I hid what he's seeing? Or perhaps it's because now ARC is on by default?

...或者我是否意外地将OP的问题改为我隐藏他所看到的问题?或者也许是因为现在ARC默认开启?

#1


17  

From the assembly code it can be seen that accessing weakPtr generates a objc_loadWeak call.

从汇编代码可以看出,访问weakPtr会生成objc_loadWeak调用。

According to the Clang documentation, objc_loadWeak retains and autoreleases the object and is equivalent to

根据Clang文档,objc_loadWeak保留并自动释放对象,相当于

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.

这不是一个特殊的NSString问题,我可以使用自定义(普通)类重现相同的行为。

#2


3  

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:

首先,不要在NSString上试验弱引用或其他内存管理行为,这个类中有太多魔法。并不是弱引用不适用于NSString,只是行为比你想象的稍微复杂,并且很容易导致不正确的结论。看到以前的这些问题:

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).

当您使用自动释放池包装代码示例并在之后记录弱字符串指针时,它确实是零。甚至可能会出现与NSString以外的类相似的行为 - 您无法保证在丢失对对象的最后一个强引用的精确时刻将清除弱引用。或者也许你是,但很难说出最后一个强引用何时消失,因为游戏中的自动释放池,正如这个例子暗示的那样(并且很好地解释了Martin的答案)。

#3


1  

when you do

当你这样做

strongPtr = [[NSString alloc] initWithString:@"abc"]

strongPtr = [[NSString alloc] initWithString:@“abc”]

you strongPtr is pointing to new allocated object, and since the previous object it was pointing too didn't get deallocated, the weak pointer still points to a valid address.

你strongPtr指向新分配的对象,并且因为它指向的前一个对象也没有被释放,所以弱指针仍然指向一个有效的地址。

btw. you can print the memory address off an object with

顺便说一句。你可以用一个对象打印内存地址

NSLog(@"%@", [NSString stringWithFormat:@"%p", theObject])

NSLog(@“%@”,[NSString stringWithFormat:@“%p”,theObject])

#4


1  

Not sure the OP's question and/or the accepted answer here is still valid, at least not as of the results I'm seeing with iOS9/Xcode7.

不确定OP的问题和/或这里接受的答案是否仍然有效,至少不是我在iOS9 / Xcode7中看到的结果。

Here's a (slightly cleaned up) version of the OP's code...

这是OP代码的一个(略微清理)版本......

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
    @autoreleasepool
    {
        NSString* __strong strongPtr = [[NSString alloc] initWithFormat:@"Life, Universe, Everything: %d", 42];
        NSString* __weak   weakPtr   = strongPtr;

        NSLog(strongPtr == weakPtr ? @"Same" : @"Different");
        NSLog(@"  StrongPtr: %@", strongPtr);
        NSLog(@"  weakPtr:   %@", weakPtr);

        NSLog(@"Changing strongPtr to something else...");
        // After this is set, there is no strong reference to the created object
        strongPtr = [[NSString alloc] initWithFormat:@"Drink: %@", @"Pan-galactic Gargle Blaster!"];

        NSLog(strongPtr == weakPtr ? @"Same" : @"Different");
        NSLog(@"  StrongPtr: %@", strongPtr);
        NSLog(@"  weakPtr:   %@", weakPtr);
    }

    return 0;
}

And here's the (truncated) output...

这是(截断的)输出......

Same
  StrongPtr: Life, Universe, Everything: 42
  weakPtr:   Life, Universe, Everything: 42

Changing strongPtr to something else...

Different
  StrongPtr: Drink: Pan-galactic Gargle Blaster!
  weakPtr:   (null)

Program ended with exit code: 0

Here accessing the weak references in the conditionals (as per the accepted answer's explanation) doesn't keep an auto-released reference around as you can see by the (null) in the output.

在这里访问条件中的弱引用(根据接受的答案的解释)不会保留自动释放的引用,如输出中的(null)所示。

...or did I accidentally change the OP's question to the point where I hid what he's seeing? Or perhaps it's because now ARC is on by default?

...或者我是否意外地将OP的问题改为我隐藏他所看到的问题?或者也许是因为现在ARC默认开启?