【问题标题】:Why aren't objects released when referencing them using __weak outside of an autorelease pool? [duplicate]为什么在自动释放池之外使用 __weak 引用对象时不释放对象? [复制]
【发布时间】:2013-06-21 05:53:26
【问题描述】:

在以下经过 ARC 处理并在 Mac OS X 10.8.4 上运行 64 位的代码中,为什么 MyObj 的实例在程序终止之前没有被释放?

#import <Foundation/Foundation.h>

@interface MyObj : NSObject
@end

@implementation MyObj
- (void)dealloc
{
    NSLog(@"MyObj dealloc'd %p", self);
}
@end

int main(int argc, const char * argv[])
{
    MyObj* obj1 = [[MyObj alloc] init];
    __weak MyObj* weakObj1 = obj1;
    NSLog(@"Use it: %p\n", weakObj1);

    // Why isn't MyObj deallocated here?

    return 0;
}

【问题讨论】:

    标签: objective-c


    【解决方案1】:

    __weak 依赖于 Objective-C 运行时函数 objc_loadWeak。来自 Clang 3.4 文档中的 Objective-C 自动引用计数:

    id objc_loadWeak(id *object);

    前置条件:object 是一个有效的指针,它要么包含一个空值 指针或已注册为 __weak 对象。

    如果 object 被注册为 __weak 对象,并且最后存储的值 object 尚未被释放或开始释放, 保留并自动释放该值并返回它。否则返回 空值。相当于如下代码:

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

    对于 object 上的 objc_storeWeak 的调用必须是原子的。

    基本原理

    加载弱引用本来就容易出现竞争 没有保留的条件。

    由于 objc_loadWeak 需要一个自动释放池,因此在使用 __weak 时必须有一个自动释放池。池可以由 NSAutoreleasePool 或 @autoreleasepool 创建。如果自动释放池不存在,那么在 objc_loadWeak 保留它之后不会释放您的对象,因此您的对象将永远不会被释放。

    以下是对上述代码的修复:

    #import <Foundation/Foundation.h>
    
    @interface MyObj : NSObject
    @end
    
    @implementation MyObj
    - (void)dealloc
    {
        NSLog(@"MyObj dealloc'd %p", self);
    }
    @end
    
    int main(int argc, const char * argv[])
    {
        @autoreleasepool {
            MyObj* obj1 = [[MyObj alloc] init];
            __weak MyObj* weakObj1 = obj1;
            NSLog(@"Use it: %p\n", weakObj1);
    
            // Now MyObj is deallocated
        }
    
        return 0;
    }
    

    【讨论】:

      【解决方案2】:

      weakObj1 在 main 结束之前不会被释放。当您使用 ARC 时,这是您应该做的,变量和对象在声明它们的块结束之前不会被释放。发生这种情况时,所有未被任何对象强引用的对象都将被释放。

      请记住,要解除分配对象,必须向其发送释放消息。如果你使用手动retain-release,MRR,你必须自己做,如果你使用自动引用计数,ARC,系统会为你做。

      【讨论】:

      • “一旦声明它的块结束,对象或变量将被释放” - 这是错误的。 strong reference 将在块的末尾释放。如果最后一个强引用是释放,则该对象将被释放。但是__weak MyObj* weakObj1 = obj1; 创建了一个不会增加保留计数的弱引用。
      • weakObj1 对 obj1 有弱引用,这意味着 weakObj1 不会增加 obj1 的保留计数;但这并不意味着weakObj1 本身没有保留计数。此保留计数将在创建对象时为 1,并且在减少到 0 之前不会被释放。在 ARC 中,它仍然取决于要释放的自动释放池。
      • 你是对的,但是答案中的那句话有误导性,也许你可以改变它。
      • 完成。谢谢指正!
      • @DiegoArmandoRincon 如果您运行问题中发布的代码,您会发现 MyObj 的实例永远不会被释放。该代码在 ARC 下编译时出现了问题。它没有被释放的原因是因为不存在自动释放池。 ARC 运行时使用的 objc_loadWeak 需要一个自动释放池。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-18
      • 1970-01-01
      • 2010-10-22
      • 1970-01-01
      • 2020-09-10
      • 2011-09-17
      • 1970-01-01
      相关资源
      最近更新 更多