0

在下面的 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;
}
4

2 回答 2

3

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

id objc_loadWeak(id *object);

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

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

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;
}
于 2013-06-21T05:53:26.193 回答
1

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

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

于 2013-06-21T06:07:28.620 回答