2012-01-24 4 views
1

아무런 서문도없이 내 프로그램에 문제가 있음을 보여주고 싶습니다. 그 단계에 대한 단계와 생각을 주석 처리했습니다. 어떻게 오류 개체가 사후에 존재(NSError * __ 강한 *) 마법

@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; 
} 

(내가 곤란에 대한 @interface 부분을 포함하지 않았다, 그것은 @implementation에서와 같은 서명 같은 방법이있다)? 나는 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 

에 대한 분해의 일부입니다.

+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 (alloc 후 실제 객체를 내 보낸)이라고 생각했습니다. – goodfella

+1

@goodfella : 무슨 뜻인지 잘 모르겠습니다. ARC에서,'__strong' 위치에 쓸 때 그 위치의 이전 값이 해제되고 새로운 값이 유지됩니다. 내 대답에서 볼 수있는 코드 스 니펫이 생성됩니다. 이제 옵티마이 저가 보유/릴리스 쌍이 불필요하다는 것을 증명할 수 있다면이를 제거 할 수 있으므로 약간 짧은 코드 스 니펫이 생깁니다. 어쨌든,이 경우 alloc'd 에러는 저장 위치가 범위를 벗어나지 않기 때문에'-testing :'내부에서 해제되지 않을 것이다. –

+0

나는 객체 소유권 정책과 혼란스러워하고 "참조로 돌아옴"상황을 함께 모을 수 없었습니다. 해명 해줘서 고마워요. – goodfella