12

NSOperation과 드로잉의 사용에 대한 조언을 듣고 있습니다.NSOperation은 UI 페인팅을 차단합니까?

메인 스레드에서 내 NSOperation 서브 클래스를 만든 다음 NSOperationQueue에 추가합니다.

NSOperationNSOperation은 몇 가지 무거운 처리를 수행합니다. main() 메서드를 몇 분 동안 반복 처리하여 끊임없이 일부 작업을 처리하기위한 것이지만 지금은 sleep (1) 루프가있는 while() 루프가 있습니다. 이것은 테스트를 위해 약 5 번만 돌아가도록 설정됩니다.

NSOperation를 생성하는 메인 (원래) 스레드는 뷰를 그리거나 UI를 업데이트합니다.

NSOperation 스레드가 알림을 사용하여 주 스레드에게 처리량을 줄 였음을 알리려고했습니다.이 알림은 while() 루프를 통과 할 때마다 한 번 전송됩니다. 잠을자는 동안 1 초에 1 번). 주 스레드 (보기)는 이러한 알림을 수신하도록 등록합니다.

통지는 즉시 주 스레드로 전달되며 비동기식으로 보입니다. 두 스레드가 동시에 예상대로 실행되는 것으로 보입니다. (NSLog()를 사용하여 각 스레드가 알림을 보내고받을 때 대략 확인합니다.)

뷰가 알림을 받고 해당 핸들러 메서드가 호출되면 간단히 정수 변수를 증가시키고이를 뷰에 표시합니다 (물론 문자열로). 테스트에서 drawRect :의 코드는이 정수 (문자열)를 화면에 잘 그립니다.

그러나 여기 : 내 문제가 (미안 그것은 여기에 도착하는 동안 조금 걸렸습니다) : 주 스레드 (보기) NSOperation에서 알림을 받으면이 테스트 정수를 업데이트하고 [self setNeedsDisplay] 호출합니다. 그러나 뷰 NSOperation 완료 될 때까지 자체 다시 그리지 않습니다! 별도의 스레드 인 NSOperation에는 주 스레드의 이벤트 루프를 차단할 수있는 기능이 없을 것으로 예상되었지만 이것이 발생하고있는 것으로 보입니다. NSOperation이 끝나고 main()이 반환되면 뷰는 마침내 직접 다시 그립니다.

아마 NSOperation를 올바르게 사용하지 않을 것입니다. "비 동시성"모드에서 사용하고 있지만, 이름에도 불구하고 이것이 여전히 새로운 스레드를 생성하고 비동기 처리가 가능하다는 것을 이해합니다.

어떤 도움이 필요하시면 언제든지 알려주십시오.

답변

10

알림에 대한 응답으로 수행되는 관찰자의 메서드가 주 스레드에서 수행되지 않습니다.

따라서이 방법에서는 performSelectorOnMainThread:withObject:waitUntilDone:을 사용하여 다른 스레드가 주 스레드에서 실행되도록 할 수 있습니다.

MyOperation.m

- (void)main { 
    for (int i = 1; i <= 5; i++) { 
     sleep(1); 
     [[NSNotificationCenter defaultCenter] postNotificationName:@"GTCNotification" object:[NSNumber numberWithInteger:i]]; 
    } 
} 

MyViewController.m

- (void)setupOperation { 
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myNotificationResponse:) name:@"GTCNotification" object:nil]; 

    NSOperationQueue *opQueue = [[NSOperationQueue alloc] init]; 
    MyOperation *myOp = [[MyOperation alloc] init]; 

    [opQueue addOperation:myOp]; 

    [myOp release]; 
    [opQueue release]; 
} 

- (void)myNotificationResponse:(NSNotification*)note { 
    NSNumber *count = [note object]; 
    [self performSelectorOnMainThread:@selector(updateView:) withObject:count waitUntilDone:YES]; 
} 

- (void)updateView:(NSNumber*)count { 
    countLabel.text = count.stringValue; 
} 
+3

원한다면 그 알림을 전부 쓰지 않고도 NSOperation 메인 메소드에서 곧바로 performSelectorOnMainThread : withObject : waitUntilDone :) 할 수 있습니다. – grzaks

0

대부분의 사람들은 어떤 디스플레이 관련 작업이 주에서 수행해야합니다 것을 알고있다 : 예를 들어

실.그러나 직접적인 결과로 드로잉에 영향을 줄 수있는 Cocoa 바인딩 속성의 변경 사항은 주 스레드에서 수정되어야합니다 (KVO 트리거는 트리거되는 스레드에서 처리되기 때문에). 이것은 대부분의 사람들에게 놀랍습니다. 특히, 메인 스레드가 아닌 다른 스레드에서 [self setNeedsDisplay]를 호출하는 것은 안전하지 않습니다.

gerry에서 언급했듯이 NSNotification은 주 스레드에서 처리되지 않고 송신 된 스레드에서 처리됩니다. 따라서 NSNotification 핸들러에서 디스플레이 관련이거나 코코아 바인딩에 영향을 줄 경우 명령을 주 스레드로 다시 보내야합니다. @performSelector 작동하지만, 큐에, 나는 더 쉽고 읽을 수있는 방법을 발견했다 : 그것은 유일한 목적이다 메인 스레드에서 호출 할 수있는 보조 도우미 함수의 정의를 피할 수

[ [ NSOperationQueue mainQueue] addOperationWithBlock:^(void) { 
    /* Your main-thread code here */ }]; 

합니다. mainQueue는 10.6 이상에서만 정의되었습니다.

관련 문제