2012-01-24 11 views
1

プリアンブルなしで私は自分のプログラムに問題があることを示したいと思います。そのステップのステップと私の考えをコメントしました。 (私は息切れのため@interface一部が含まれていなかった、それは@implementationと同じシグネチャを持つ同じメソッドを持っている)(NSError * __ strong *)magic

@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 *を使用して行くことが正しい方法であることを理解し、状況はその場合には些細なものですが、このコードのコンパイラの推論は、判断の間違いはどこですか?

これは少し人工的な質問ですが、私は頭からこのような状況を捨てることはできません、私は何かを失っていると思います。ここで

は私が正しく理解している場合、1つのオブジェクトのみがこの方法であり、それが明確に自動解放または何か他のものではない、リリースさ-[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 

のために解体の一部です。

+0

ところで、ARCの下では、すべてのオブジェクトスタック変数はnilに初期化されるので、 'NSError * e'の宣言で' = nil'と言う必要はありません。 –

答えて

3

私はあなたが何がリリースされているのか混乱していると思う。アセンブリ出力を確認したところ、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が解放されています。

+0

興味深いですが、どこでコンパイラの動作を読むことができますか?私は、参照によって与えられたオブジェクトが強ければ、それが保持されている(この例では単にnilを保持している)、解放された(allocの後に実際のオブジェクトを解放した)と考えた。 – goodfella

+1

@goodfella:あなたが何を意味するのかはっきりしていません。 ARCでは、 '__strong'位置に書き込むと、その位置の前の値が解放され、新しい値が保持されます。それはあなたが私の答えに見えるコードスニペットを生成します。今、オプティマイザが保持/解放のペアが不要であると証明できる場合は、それらを削除することができます。これにより、少し短いコードスニペットになります。とにかく、この場合、alloc'dエラーは '-testing:'の内部で解放されません。なぜなら、その格納場所が範囲外にならないからです。 –

+0

私はオブジェクト所有ポリシーと自分自身を混乱させ、「参照による復帰」の状況はそれらを一緒に組み立てることができませんでした。 – goodfella