2012-01-11 2 views
9

다음 코드를 고려 액세스 할 때 블록 속성 직접 충돌을 설정하면아이폰 OS :

self.someA = [[ClassA alloc] init]; 
[self.someA giveBlock:^{ 
    NSLog(@"self = %@", self); 
}]; 
dispatch_async(dispatch_get_main_queue(), ^{ 
    self.someA.blockCopy(); 
    self.someA = nil; 
}); 

를 I ARC가 활성화 된 O3을 실행하면 iOS에서 self.someA.blockCopy(); 전화 (objc_retain)가 실행되는 동안 충돌합니다. 왜?

이제 나는 사람들이 내가 self.blockCopy = inBlock으로 설정해야한다고 말할 것임을 알았지 만, ARC가 올바른 일을해야한다고 생각했습니다.

 .align 2 
     .code 16 
     .thumb_func  "-[ClassA giveBlock:]" 
"-[ClassA giveBlock:]": 
     push {r7, lr} 
     movw r1, :lower16:(_OBJC_IVAR_$_ClassA.blockCopy-(LPC0_0+4)) 
     mov  r7, sp 
     movt r1, :upper16:(_OBJC_IVAR_$_ClassA.blockCopy-(LPC0_0+4)) 
LPC0_0: 
     add  r1, pc 
     ldr  r1, [r1] 
     add  r0, r1 
     mov  r1, r2 
     blx  _objc_storeStrong 
     pop  {r7, pc} 

차례로 블록에 retain하고 이전 블록에 release을 수행 objc_storeStrong를 호출 : 나는 어셈블리를 보면 (하는 ARMv7은)는이처럼 보이는 giveBlock: 방법에서 생산. 내 생각 엔 ARC가 정상적인 objc_retain 대신 objc_retainBlock을 호출해야한다고 생각하기 때문에 ARC가 블록 속성임을 올바르게 알지 못한다는 것입니다.

아니면 완전히 틀렸고 실제로 ARC가 문서화 작업을하고 있으며 방금 잘못된 방식으로 읽었습니까?

대단히 환영합니다.이 점이 다소 흥미로울 것입니다.

참고할 사항 : 그것은 O0를 구축 충돌하지 않는

  • OS X의에 충돌하지 않습니다

    • .
  • 답변

    12
    - (void)giveBlock:(void(^)())inBlock { 
        blockCopy = inBlock; 
    } 
    

    당신은 할당 또는이 함수에 전달 될 때 두 블록을 복사해야합니다. ARC는 return on heap-on-return 문제를 해결하지만 인수 (C의 특이성을 보장 할 수는 없습니다)에서 그렇게하지 않습니다.

    특정 환경에서 충돌하지 않는 것은 단지 우연입니다. 블록의 스택 버전을 덮어 쓰지 않는 한 충돌하지 않습니다. 이 문제의 확실한 징후는 최적화가 해제 된 상태에서 충돌이 발생했을 때입니다. 최적화가 해제되면 컴파일러는 주어진 범위 내에서 스택 메모리를 재사용하지 않아 메모리가 "유효"한 후에 오랫동안 사용하게됩니다. 그것은 정상적인 objc_retain보다는 objc_blockRetain 을 할 수없는 이유


    나는 여전히 매우하지만, 이해가 안 돼요. 컴파일러는 결국 유형을 알고 있습니다.

    저는 잠재적 인 문제임을 확신합니다. 블록이 잠재적으로 다른 블록을 포함하여 많은 상태를 캡처하면 Block_copy()는 실제로 일 수 있으며 실제로은 실제로 일 수 있습니다.

    e.e.당신이 뭔가가 있다면 : 단순히 때문에 할당의)

    BlockType b = ^(...) { ... capture lots of gunk ... }; 
    SomeRandomFunc(b); 
    

    을 ... 그리고는 Block_copy을 (암시, 그것이 불가능 병적 인 성능 문제의 위험없이 지속적으로 블록을 사용할 수 있도록합니다. 컴파일러가 SomeRandomFunc()이 동기식 또는 비동기식인지 여부를 알 수있는 방법이 없기 때문에 자동으로이를 관리 할 방법이 없습니다 (현재로서는이 잠재적 인 트립 와이어를 제거하는 것이 바람직합니다).

    +0

    하지만 할당 할 때 'objc_storeStrong'을 통과하는 것을 보는 데 약간 놀랐습니다. 제대로 된 일을 할 수 없었습니다. – mattjgalloway

    +0

    +1 흥미 롭습니다! – Till

    +0

    내가 이해 한 (잠시 동안), 컴파일러가 모든 경우에 올바르게 작동하는 코드를 방출하지 못하도록하는 경우가 있습니다. ARC 하에서 모래의 딱딱한 선은 주어진 코드 패턴이 항상 모든 곳에서 작동한다는 것을 컴파일러가 정확하게 증명할 수 있어야합니다. 이 경우 주어진 호출 사이트를 통해 전달 된 스택 전용 블록 인수 ('objc_storeStrong() '포함)에 대한 유효한 사용이 있기 때문에 그렇게 할 수 없습니다. – bbum