【问题标题】:(NSError *__strong *)magic(NSError *__strong *)magic
【发布时间】:2012-01-24 21:14:08
【问题描述】:

没有任何前言,我想向您展示我在程序中遇到的问题,我注释掉了步骤和我对这些步骤的想法。 (为了简短起见,我没有包含@interface 部分,它具有与@implementation 相同的签名相同的方法)

@implementation Dummy

- (int)testing:(NSError *__strong *)error 
{
    *error = [[NSError alloc] initWithDomain:@"hello" code:42 userInfo:nil]; 
    // 3. retain count = 1

    // 4. because of ARC 'error' object was released for this time 
    // (assembly output is my proof) object is deallocated
    // retain count = 0

    return 0;
}

@end

int main()
{
    NSError *e = nil; // 1. retain count = 0 (obviously)
    Dummy *dummy = [[Dummy alloc] init];

    [dummy testing:&e]; // 2. passing reference to an error object

    // 'e' for this time has to be just a trash, or nil maybe, 
    // but next log gives me correct output: 
    NSLog(@"%@ %li", [e domain], [e code]); // 'hello 42'

    return 0;
}

错误对象死后如何存在?我知道使用NSError *__autoreleasing * 是正确的方法,在这种情况下情况将是微不足道的,但是编译器如何推理这段代码,我的判断错误在哪里?

这是一个人为的问题,但我无法将这种情况从我的脑海中抛开,我想我正在失去一些东西。

这是-[Dummy testing:]的部分反汇编

callq  0x100000e8c <dyld_stub_objc_msgSend>
mov    -0x18(%rbp),%rcx
mov    (%rcx),%rdx
mov    %rax,(%rcx)
mov    %rdx,%rdi
callq  0x100000e92 <dyld_stub_objc_release>
mov    -0x24(%rbp),%eax
add    $0x40,%rsp
pop    %rbp
retq   

如果我理解正确的话,这个方法中只有一个对象,而且很明显是释放的,不是自动释放的什么的。

【问题讨论】:

  • 顺便说一句,在 ARC 下,所有对象堆栈变量都被初始化为 nil,所以你不需要在 NSError *e 的声明中说 = nil

标签: objective-c automatic-ref-counting


【解决方案1】:

我怀疑您对发布的内容感到困惑。我刚刚检查了程序集输出,有一个对objc_release() 的调用,尽管我对x86 程序集不够熟悉,无法准确地跟踪正在发生的事情。但是,我确实知道这里的代码预计会发出类似于以下内容的内容:

NSError *temp = [[NSError alloc] initWithDomain:@"hello" code:42 userInfo:nil];
[*error release];
*error = [temp retain];
[temp release];

当然优化器会将其缩小到

NSError *temp = ...
[*error release];
*error = temp;

所以我认为您看到了对objc_release() 的调用,并认为您新分配的错误正在被释放。它不是。 *error 的先前值在新分配的错误放置在该位置之前被释放。

【讨论】:

  • 有趣的是,我在哪里可以了解编译器的这种行为?我想如果通过引用给出的对象是强的,它会被保留(在这个例子中只是保留 nil),然后释放(在 alloc 之后释放实际对象)。
  • @goodfella:不太清楚你的意思。在 ARC 下,当写入 __strong 位置时,该位置的先前值将被释放并保留新值。这会产生您在我的答案中看到的代码 sn-p。现在,如果优化器可以证明保留/释放对是不必要的,它可以删除它们,这导致我的代码稍微短一些。无论如何,在这种情况下,分配的错误不会在 -testing: 中释放,因为它的存储位置不会超出范围。
  • 我对对象所有权政策和“按引用返回”的情况感到困惑,只是无法将它们组装在一起,谢谢您的澄清。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-15
  • 1970-01-01
相关资源
最近更新 更多