在自动释放池之外使用__weak引用它们时,为什么没有释放对象?

时间:2013-06-21 05:53:26

标签: objective-c

在下面的代码中,ARC'd并在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;
}

2 个答案:

答案 0 :(得分:3)

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

  

id objc_loadWeak(id * object);

     

前提条件对象是一个有效的指针,它包含一个null   指针或已注册为 __弱对象。

     

如果对象被注册为 __弱对象,并且存储了最后一个值   进入对象尚未解除分配或开始解除分配,   保留和自动释放,重视并返回它。否则返回   空值。相当于以下代码:

id objc_loadWeak(id *object) {
    return objc_autorelease(objc_loadWeakRetained(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;
}

答案 1 :(得分:1)

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

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