Objective-C:弱引用属性不按预期工作

10

可能重复:
为什么iOS中的弱NSString属性不会被释放?

我是Objective C的新手,有一些问题我自己无法回答。 我有一段用于测试__weak变量的代码块(当然我使用ARC):

NSString *myString = [[NSString alloc] initWithFormat:@"John"];
NSString * __weak weakString = myString;
myString = nil; //<-- release the NSString object
NSLog(@"string: %@", weakString);
以上代码的输出与预期相符,因为weakString是一个弱引用变量。
2013-01-02 11:42:27.481 ConsoleApp[836:303] string: (null)

但是当我将代码修改为这样:

NSString *myString = [[NSString alloc] initWithFormat:@"John"];
NSString * __weak weakString = myString;
NSLog(@"Before: %@", weakString); //<--- output to see if the __weak variable really works.
myString = nil;
NSLog(@"After: %@", weakString);

输出结果完全不是我期望的:

2013-01-02 11:46:03.790 ConsoleApp[863:303] Before: John
2013-01-02 11:46:03.792 ConsoleApp[863:303] After: John

后面那个 NSLog 的输出必须是 (nil),而不是 "John"。我已经尝试在许多文档中搜索,但没有找到这种情况的答案。有人可以给出一个合理的解释吗?提前感谢。


@jrturton:我认为这不是链接问题的重复。那里的问题是使用常量NSString,由于性能优化而不参与通常的内存管理。这里的发布者使用initWithFormat来避免这个问题。 - zoul
我曾经读过(但这次找不到了)另一个重复的问题,其中NSString的某些优化会阻止其正常工作。如果OP尝试使用不同类型的对象,我认为一切都会按预期工作。我会继续搜索... - jrturton
也可以在这里查看:https://dev59.com/S2DVa4cB1Zd3GeqPbDdf - jrturton
1
那个在https://dev59.com/S2DVa4cB1Zd3GeqPbDdf的问题对我来说已经得到了解决。我很好地理解了**initWithFormat**和**stringWithFormat**的概念。无论如何,感谢你的关心,我很感激。 :) - hoang Cap
2个回答

7

NSLog函数会将传递的NSString对象放到自动释放池中进行保留。因此,该零弱变量直到自动释放池被清空后才会被置为零。例如:

__weak NSString* weakString = nil;

@autoreleasepool {
    NSString* myString = [[NSString alloc] initWithFormat:@"Foo"]; // Retain count 1
    weakString = myString;         // Retain count 1
    NSLog(@"A: %@", weakString);   // Retain count 2
    NSLog(@"B: %@", weakString);   // Retain count 3
    myString = nil;                // Retain count 2
    NSLog(@"C: %@", weakString);   // Retain count 3

    NSAssert(weakString != nil, @"weakString is kept alive by the autorelease pool");
} 

// retain count 0
NSAssert(weakString == nil, @"Autorelease pool has drained.");

为什么NSLog将字符串放入自动释放池中?这是一个实现细节。

您可以使用调试器或工具来跟踪NSString实例的保留计数。确切的保留计数并不重要,但它确实揭示了一些幕后情况。重要的是,当自动释放池被排空时,NSString实例将被释放。


1
是的,这基本上解释了它,我认为NSLog()会增加其参数的保留计数,但你的答案更合理。非常感谢Darren。 - hoang Cap

0

我认为这只是一些实现细节。你的弱变量正在被清除,但不是立即清除。例如,这个可以按预期工作:

NSString *myString = [[NSString alloc] initWithFormat:@"John"];
NSString * __weak weakString = myString;
@autoreleasepool {
    NSLog(@"Before: %@", weakString);
    myString = nil;
}
NSLog(@"After: %@", weakString); // nil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接