objective-c - 与 ARC 不一致的对象释放?

标签 objective-c automatic-ref-counting

我在一个简单的 Mac OSX 10.7 命令行应用程序上玩内存(取消)分配的东西,使用 Xcode 版本 4.2.1 启用 ARC 和默认build设置。我无法根据我对 ARC 的理解来解释我的行为,所以我希望有人能解释这里发生了什么。

首先,在下面的代码中我得到了我期望的行为(请注意 NLog() 输出在相应语句后的注释中给出)

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
    NSObject *objPtr1 = [[NSObject alloc] init];
    NSObject *objPtr2 = objPtr1; 
    __weak NSObject *weakRef = objPtr1;
    NSLog(@"%@", [objPtr1 description]); // <NSObject: 0x1001107d0>
    objPtr1 = nil;
    NSLog(@"%@", [objPtr2 description]); // <NSObject: 0x1001107d0>
    objPtr2 = nil;
    NSLog(@"%@", [weakRef description]); // (null)
    return 0;
}

所以在上面,在分配 weakRef 之后,NSObject 实例有两个指向它的强指针,因此保留计数为 2。在将 objPtr1 清零之后,仍然有一个指向该实例的保留指针,所以它仍在内存中并且响应描述消息。在 nil-ing objPtr2 之后,没有指向该对象的强指针并且它被释放(我假设它是,因为 weakRef 已被归零)。到目前为止,还不错。

现在,相同的代码稍作改动:

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
    NSObject *objPtr1 = [[NSObject alloc] init];
    NSObject *objPtr2 = objPtr1; 
    __unsafe_unretained NSObject *weakRef = objPtr1; // __unsafe_unretained instead of just __weak
    NSLog(@"%@", [objPtr1 description]); // <NSObject: 0x1001107d0>

    objPtr1 = nil;
    NSLog(@"%@", [objPtr2 description]); // <NSObject: 0x1001107d0>

    objPtr2 = nil;
    NSLog(@"%@", [weakRef description]); // <NSObject: 0x1001107d0>
    //why was the object instance not deallocated and the preceding statement not crash the program?
    return 0;
}

我原以为 weakRef 会变成一个悬空指针,通过它发送一条消息会导致程序在第三个 NSLog() 语句中崩溃,但对象实例似乎仍然存在并且运行良好。

还有一点我觉得很奇怪:

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{

    NSObject *objPtr1 = [[NSObject alloc] init];
    NSObject *objPtr2 = objPtr1; 
    __weak NSObject *weakRef = objPtr1; // __weak again
    NSLog(@"%@", [weakRef description]); // <NSObject: 0x1001107d0>

    objPtr1 = nil;
    NSLog(@"%@", [weakRef description]); // <NSObject: 0x1001107d0>

    objPtr2 = nil;
    NSLog(@"%@", [weakRef description]); // <NSObject: 0x1001107d0>

    return 0;

}

最后一段代码与第一段代码类似(使用归零的 __weak 指针);唯一的区别是在三个 NSLog() 调用中的每一个中,描述消息都是通过 weakRef 发送到对象的。但这一次,即使在删除了两个强引用之后,对象也没有被释放(因为它仍然通过 weakRef 响应消息)。

那么这里发生了什么?

最佳答案

如果反汇编 A.R.C. 生成的代码,对弱变量的每次访问都包含在对此函数的调用中:

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

这会检查对象是否已经被释放,如果没有,则保留并自动释放它,以防止过早释放。

因此,在您的第三个示例中,对 weakRef 方法的早期调用导致其保留计数增加,因此将您的指针置零不会导致它被释放。

关于objective-c - 与 ARC 不一致的对象释放?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9173120/

相关文章:

ios - iOS <5上具有ARC的Twitter集成

iphone - 字符已在范围内吗?

swift - 为什么我从将弱 self 传递到静态函数的闭包中得到一个保留周期?

iOS 7.0 和 ARC : UITableView never deallocated after rows animation

objective-c - 分段控制不起作用

objective-c - 对于非 CF 类型,使用匹配的 CFBridging 调用来传入和传出 ARC 是否安全?

iphone - 当变量在 ARC 中同时为 __block 和 __weak 时,这意味着什么?

objective-c - 我怎样才能告诉 MagicalRecord 不要使用基于文件的核心数据,而是使用内存设置?

objective-c - LLVM 循环优化错误?

objective-c - 如何在 Objective C 中添加图像作为按钮?