28

我有点固执,但我想很好地理解弱引用和强引用,所以我再次问你。

考虑一下:

__weak NSString* mySecondPointer = myText;   
NSLog(@"myText: %@", myText);

结果myText: (null)很明显——弱引用在赋值后被设置为空,因为没有对指向对象的强引用。

但在这种情况下:

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

输出:

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   // <== ??

我的问题:

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


我试过那个:(但我想添加评论并不好)。我在@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);

输出:

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

4 回答 4

17

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

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

id objc_loadWeak(id *object) {
  return objc_autorelease(objc_loadWeakRetained(object));
}

这(希望)解释了为什么两者

if(strongPtr == weakPtr) ...

NSLog(@"weakPtr: %@", weakPtr);

创建其他自动发布的引用。

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

于 2013-03-07T09:21:11.293 回答
3

首先,不要在 上试验弱引用或其他内存管理行为NSString,那个类有太多的魔力。并不是说弱引用不起作用NSString,只是行为比您预期的要复杂一些,并且很容易导致错误的结论。请参阅这些先前的问题:

当您使用自动释放池包装代码示例并随后记录弱字符串指针时,nil确实如此。甚至可能会出现与类以外的类似行为的情况NSString——您根本无法保证弱引用会在您丢失对对象的最后一个强引用的那一刻被清除。或者也许你是,但是很难说最后一个强引用到底什么时候消失了,因为自动释放池正在发挥作用,正如这个例子所暗示的那样(马丁的回答很好地解释了)。

于 2013-03-07T08:46:43.650 回答
1

当你这样做时

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

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

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

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

于 2013-03-07T08:46:04.923 回答
1

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

这是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;
}

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

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

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

...或者我是否不小心将 OP 的问题更改为我隐藏了他所看到的内容?或者可能是因为现在 ARC 默认开启?

于 2016-06-01T20:25:28.067 回答