【问题标题】:Objective-C: Weak attritube don't work as expected [duplicate]Objective-C:弱属性不能按预期工作[重复]
【发布时间】:2012-12-16 12:31:12
【问题描述】:

可能重复:
Why do weak NSString properties not get released in iOS?

我是 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 来避免这个问题。
  • 我读过(但这次找不到)另一个这样的骗局,其中 NSString 的一些优化阻止了这项工作。如果 OP 尝试不同类型的对象,我怀疑一切都会按预期工作。我会继续寻找......
  • stackoverflow.com/questions/9202810/… 中的那个问题在我之前得到了解决。我很理解 initWithFormatstringWithFormat 的概念。不管怎样,谢谢你的关心,我很感激。 :)

标签: ios weak-references strong-references


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    NSLog 函数将传递的 NSString 保留在自动释放池中。因此,在自动释放池耗尽之前,zeroing-weak 变量不会被归零。例如:

    __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 实例在自动释放池耗尽时被释放。

    【讨论】:

    • 是的,这几乎解释了它,我认为 NSlog() 会增加其参数的保留计数,但你的回答更合理。非常感谢达伦。
    猜你喜欢
    • 2010-12-19
    • 1970-01-01
    • 2019-01-06
    • 2011-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多