45

내 응용 프로그램에서 GCD와 performSelectorOnMainThread : waitUntilDone을 ​​모두 사용했으며 상호 교환 가능하다고 생각하는 경향이 있습니다. 즉 performSelectorOnMainThread : waitUntilDone은 Obj입니다. -C 래퍼를 GCD C 구문으로 변환합니다. 이 두 명령을 동등한 것으로 생각했습니다.GCD (Grand Central Dispatch) vs. performSelector - 더 나은 설명이 필요합니다.

dispatch_sync(dispatch_get_main_queue(), ^{ [self doit:YES]; }); 


[self performSelectorOnMainThread:@selector(doit:) withObject:YES waitUntilDone:YES]; 

잘못된 것입니까? 즉, performSelector * 명령과 GCD 명령의 차이점이 있습니까? 나는 그들에 대한 많은 문서를 읽었지만 확실한 답을 아직 보지 못했다.

+5

withObject : YES는 작동하지 않으며 최소한 경고를 제공해야합니다. 이것은 수신기에 임의의 인수를 보낼 수있는 GDC의 장점 중 하나입니다. – FelixLam

+0

그래, NSNumber에 포장해야 겠어. 하지만, 그 부분을 무시하고, 다른 것은 다른 것입니까? 그래도 좋은 지적이다. – akaru

답변

20

performSelectorOnMainThread: 주 스레드의 개체에 메시지를 보내려면 GCD를 사용하십시오.

- (void) performSelectorOnMainThread:(SEL) selector withObject:(id) obj waitUntilDone:(BOOL) wait { 
    [[NSRunLoop mainRunLoop] performSelector:selector target:self withObject:obj order:1 modes: NSRunLoopCommonModes]; 
} 

그리고 performSelector:target:withObject:order:modes:에, 문서 상태 : 다음 documentation이 방법이 구현 말한다 방법

는 여기

이 방법에 aSelector 메시지를 수행 할 수있는 타이머를 설정을 현재의 thread의 다음 실행 루프 반복의 시작에서 루프를 실행하십시오. 타이머는 modes 매개 변수로 지정된 모드에서 실행되도록 구성됩니다. 타이머가 실행되면 스레드가 실행 루프에서 메시지를 대기열에서 빼내고 선택기를 수행하려고 시도합니다. 실행 루프가 실행 중이고 지정된 모드 중 하나에서 성공하면 성공합니다. 그렇지 않으면 타이머는 실행 루프가 해당 모드 중 하나에있을 때까지 대기합니다.

65

야곱은 같은 것처럼 보일 수 있지만 다른 것들을 지적합니다. 사실 메인 스레드에서 이미 실행중인 경우 주 스레드로 작업을 보내는 방식에 상당한 차이가 있습니다.

나는 최근에이 문제에 시달렸는데, 때로는 메인 스레드의 어떤 것으로부터 가끔씩 실행되는 일반적인 방법이있다. 특정 UI 업데이트를 보호하기 위해 아무런 문제없이 -performSelectorOnMainThread:을 사용했습니다.

주 큐에서 dispatch_sync을 사용하도록 전환하면이 메서드가 주 큐에서 실행될 때마다 응용 프로그램이 교착 상태가됩니다. dispatch_sync에 설명서를 읽고, 우리는 다음을 참조하십시오

이 함수를 호출하고 교착 상태에 현재 큐 결과를 대상으로. -performSelectorOnMainThread: 위해 우리

는 지정

부울 기다리

여부 지정된 셀렉터 메인 쓰레드에 수신기에서 수행 된 후까지 현재 스레드 블록 . 이 스레드를 차단하려면 YES를 지정하십시오. 그렇지 않으면 은 NO를 지정하여이 메소드가 즉시 을 리턴하도록합니다.

현재 스레드가 기본 스레드이기도하고이 매개 변수에 대해 YES를 지정하면 메시지는 으로 전달되고 즉시 처리됩니다.

난 아직도 GCD의 우아함을 선호하는, 더 나은 컴파일 시간 검사는 제공 등 인수, 대한의 유연성은, 그래서 교착 상태 방지하기 위해이 작은 도우미 함수 만든 :

void runOnMainQueueWithoutDeadlocking(void (^block)(void)) 
{ 
    if ([NSThread isMainThread]) 
    { 
     block(); 
    } 
    else 
    { 
     dispatch_sync(dispatch_get_main_queue(), block); 
    } 
} 

업데이트 : Dave Dribin이 caveats section ondispatch_get_current_queue()을 지적함에 따라 위 코드에서 [NSThread isMainThread]으로 변경했습니다.

나는 다음 원래 방법에 실행 된 스레드 것에 대해 걱정하지 않고, 내가 주 스레드에서 보안을 필요로하는 작업을 수행 할 수

runOnMainQueueWithoutDeadlocking(^{ 
    //Do stuff 
}); 

를 사용합니다.

+1

메인 스레드에서 @Joe -'dispatch_sync()'가 백그라운드 스레드의 값을 기다리는 동안 메인 스레드의 스레드가 ('dispatch_sync()'또는 다른 것을 통해) 차단되면 여전히 응용 프로그램 내에서 교착 상태가 발생할 수 있습니다. 이것은 거의 불가능하지만 여전히 가능합니다. 그것은 다른 스레드가 무언가를하기를 기다리는 두 스레드의 표준 스레딩 문제이므로 아무것도 수행되지 않습니다. –

+0

@Joe - 예, 메인이 아닌 대기열 또는 스레드에서 완전히 실행중인 경우 위에 언급 한 코드가 필요하지 않습니다. 지금 막 언급 한 교착 상태 문제는이 코드에도 문제가됩니다. 그것은 건축 학적 문제입니다. 의견이 나오는 한,이 메타 질문 : http://meta.stackexchange.com/questions/43019/how-do-comment-replies-work를 참조하십시오. –

+11

패먼트 리 오버 플로우 : 추악한'void (^ block) (void)'대신에'dispatch_block_t'를 인자 타입으로 사용할 수 있습니다. –

1

GCD의 방식은 처리가 더 효율적이고 쉬우 며 iOS4에서만 사용할 수있는 반면 performSelector는 이전 iOS 및 최신 iOS에서 지원됩니다.

관련 문제