[ios] NSRunLoop 이해

누구든지 설명 할 수 있습니까 NSRunLoop? 그래서 내가 아는 것처럼 NSRunLoop뭔가 연결되어 NSThread있지 않습니까? 그래서 내가 같은 스레드를 만든다고 가정합니다

NSThread* th=[[NSThread alloc] initWithTarget:self selector:@selector(someMethod) object:nil];
[th start];

-(void) someMethod
{
    NSLog(@"operation");
}

이 스레드가 작업을 마치고 나면? 왜 사용 RunLoops하거나 어디에 사용합니까? Apple 문서에서 읽은 내용이 있지만 명확하지 않으므로 가능한 한 간단하게 설명하십시오.



답변

실행 루프는 시스템 입력 소스 (소켓, 포트, 파일, 키보드, 마우스, 타이머 등)를 처리하는 메커니즘을 제공하는 추상화입니다.

각 NSThread에는 currentRunLoop 메서드를 통해 액세스 할 수있는 자체 실행 루프가 있습니다.

일반적으로 I / O 처리에 사용할 실행 루프를 지정할 수있는 일부 (네트워킹) 구성 요소가 있지만 실행 루프에 직접 액세스 할 필요가 없습니다.

주어진 스레드에 대한 실행 루프는 하나 이상의 입력 소스에 데이터 또는 이벤트가있을 때까지 기다린 다음 적절한 입력 핸들러를 실행하여 “준비된”각 입력 소스를 처리합니다.

그런 다음 루프로 돌아가서 다양한 소스의 입력을 처리하고 수행 할 작업이 없으면 “휴면”합니다.

이것은 매우 높은 수준의 설명입니다 (너무 많은 세부 사항을 피하려고합니다).

편집하다

댓글을 다루려는 시도. 나는 그것을 산산조각 냈다.

  • 스레드 내부에서 루프를 실행하기 위해 액세스 / 실행 만 할 수 있다는 의미입니까?

과연. NSRunLoop은 스레드로부터 안전하지 않으며 루프를 실행하는 스레드의 컨텍스트에서만 액세스해야합니다.

  • 루프를 실행하기 위해 이벤트를 추가하는 방법에 대한 간단한 예가 있습니까?

포트를 모니터링하려면 해당 포트를 실행 루프에 추가하면 실행 루프가 해당 포트의 활동을 감시합니다.

- (void)addPort:(NSPort *)aPort forMode:(NSString *)mode

다음을 사용하여 명시 적으로 타이머를 추가 할 수도 있습니다.

- (void)addTimer:(NSTimer *)aTimer forMode:(NSString *)mode
  • 그런 다음 루프로 돌아 간다는 의미는 무엇입니까?

실행 루프는 모드에 따라 반복 할 때마다 모든 준비 이벤트를 처리합니다. 일반적인 대답의 범위를 약간 벗어난 실행 모드에 대해 알아 보려면 설명서를 참조해야합니다.

  • 스레드를 시작할 때 실행 루프가 비활성화됩니까?

대부분의 애플리케이션에서 메인 런 루프는 자동으로 실행됩니다. 그러나 실행 루프를 시작하고 회전하는 스레드에 대한 수신 이벤트에 응답하는 것은 사용자의 책임입니다.

  • 스레드 외부의 스레드 실행 루프에 일부 이벤트를 추가 할 수 있습니까?

여기서 무슨 뜻인지 잘 모르겠습니다. 런 루프에 이벤트를 추가하지 않습니다. 입력 소스와 타이머 소스를 추가합니다 (런 루프를 소유 한 스레드에서). 그런 다음 실행 루프는 활동을 감시합니다. 물론 다른 스레드 및 프로세스에서 데이터 입력을 제공 할 수 있지만 입력은 실행 루프를 실행하는 스레드에서 해당 소스를 모니터링하는 실행 루프에 의해 처리됩니다.

  • 그것은 때때로 내가 한동안 스레드를 차단하기 위해 실행 루프를 사용할 수 있다는 것을 의미합니까?

과연. 실제로 실행 루프는 이벤트 핸들러가 반환 될 때까지 이벤트 핸들러에 “유지”됩니다. 모든 앱에서 간단히 볼 수 있습니다. 휴면 상태 인 모든 IO 작업 (예 : 버튼 누름)에 대한 핸들러를 설치합니다. 해당 메서드가 완료 될 때까지 기본 실행 루프 (및 전체 UI)를 차단합니다.

모든 런 루프에도 동일하게 적용됩니다.

런 루프에 대한 다음 문서를 읽는 것이 좋습니다.

https://developer.apple.com/documentation/foundation/nsrunloop

스레드 내에서 사용되는 방법 :

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html#//apple_ref/doc/uid/10000057i-CH16-SW1


답변

실행 루프는 무엇 분리 인터랙티브 에서 응용 프로그램
명령 줄 도구를.

  • 명령 줄 도구는 매개 변수와 함께 시작되고 해당 명령을 실행 한 다음 종료됩니다.
  • 대화 형 앱 은 사용자 입력을 기다렸다가 반응 한 다음 다시 대기합니다.

에서 여기

사용자가 탭하고 그에 따라 응답 할 때까지 기다렸다가, completeHandler를 얻고 그 결과를 적용 할 때까지 기다렸다가 타이머를 얻고 기능을 수행 할 때까지 기다릴 수 있습니다. 런 루프가 없으면 사용자 탭을 듣거나 기다릴 수없고, 네트워크 호출이 발생할 때까지 기다릴 수 없으며, DispatchSourceTimer또는 사용하지 않는 한 x 분 안에 깨어날 수 없습니다.DispatchWorkItem

또한 이 의견에서 :

백그라운드 스레드에는 자체 실행 루프가 없지만 하나만 추가 할 수 있습니다. 예 : AFNetworking 2.x 가 해냈습니다. 백그라운드 스레드에서 NSURLConnection 또는 NSTimer에 대해 시도 된 진정한 기술이지만 최신 API가 그렇게 할 필요가 없기 때문에 더 이상 직접 수행하지 않습니다. 그러나 URLSession이 수행하는 것처럼 보입니다. 예를 들어 여기에는 간단한 요청 이 있습니다. 메인 대기열에서 [이미지의 왼쪽 패널 참조] 완료 핸들러를 실행하고 백그라운드 스레드에서 실행 루프가 있음을 알 수 있습니다.


구체적으로는 “백그라운드 스레드에는 자체 런 루프가 없습니다”. 다음 타이머는 비동기 디스패치를 위해 실행되지 않습니다 .

class T {
    var timer: Timer?

    func fireWithoutAnyQueue() {
        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false, block: { _ in
            print("without any queue") // success. It's being ran on main thread, since playgrounds begin running from main thread
        })
    }

    func fireFromQueueAsnyc() {
        let queue = DispatchQueue(label: "whatever")
        queue.async {
            self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false, block: { (_) in
                print("from a queue — async") // failed to print
            })
        }
    }

    func fireFromQueueSnyc() {
        let queue = DispatchQueue(label: "whatever")
        queue.sync {
            timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false, block: { (_) in
                print("from a queue — sync") // success. Weird. Read my possible explanation below
            })
        }
    }

    func fireFromMain() {
        DispatchQueue.main.async {
            self.timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false, block: { (_) in
                print("from main queue — sync") //success
            })
        }
    }
}

sync블록이 실행 되는 이유는 다음과 같습니다.

동기화 블록은 일반적으로 소스 대기열 내에서 실행 됩니다. 이 예에서 소스 대기열은 기본 대기열이고 어떤 대기열 이든 대상 대기열입니다.

RunLoop.current모든 디스패치에 로그인 했는지 테스트하기 위해.

동기화 디스패치는 메인 큐 와 동일한 런 루프를 가졌습니다 . 비동기 블록 내의 RunLoop은 다른 인스턴스와 다른 인스턴스였습니다. 왜 RunLoop.current다른 값을 반환 하는지 생각할 수 있습니다 . 공유 가치 아닌가요 !? 좋은 질문입니다! 더 읽어보기 :

중요 사항:

클래스 속성은 current 전역 변수 아닙니다.

현재 스레드 의 실행 루프를 반환합니다 .

상황에 따라 다릅니다. 스레드 범위 즉, 스레드 로컬 저장소 내에서만 볼 수 있습니다 . 이에 대한 자세한 내용은 여기 를 참조 하십시오 .

이것은 타이머의 알려진 문제입니다. 사용하면 같은 문제가 없습니다.DispatchSourceTimer


답변

RunLoops는 상황이 발생하는 상자와 비슷합니다.

기본적으로 RunLoop에서 일부 이벤트를 처리 한 다음 반환합니다. 또는 시간 제한에 도달하기 전에 이벤트를 처리하지 않으면 반환합니다. 비동기 NSURLConnections, 현재 루프를 방해하지 않고 백그라운드에서 데이터를 처리하는 것과 비슷하지만 동시에 데이터가 동 기적으로 필요하다고 말할 수 있습니다. 비 동기화 NSURLConnection하고 호출 시간에 데이터를 제공 하는 RunLoop의 도움으로 수행 할 수 있습니다 . 다음과 같이 RunLoop을 사용할 수 있습니다.

NSDate *loopUntil = [NSDate dateWithTimeIntervalSinceNow:0.1];

while (YourBoolFlag && [[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode beforeDate:loopUntil]) {
    loopUntil = [NSDate dateWithTimeIntervalSinceNow:0.1];
}

이 RunLoop에서는 다른 작업을 완료하고 YourBoolFlagfalse로 설정할 때까지 실행됩니다 .

마찬가지로 스레드에서 사용할 수 있습니다.

도움이 되었기를 바랍니다.


답변

실행 루프는 스레드와 관련된 기본 인프라의 일부입니다. 실행 루프는 작업을 예약하고 수신 이벤트 수신을 조정하는 데 사용하는 이벤트 처리 루프입니다. 실행 루프의 목적은 할 작업이있을 때 스레드를 바쁘게 유지하고 작업이 없을 때 스레드를 절전 모드로 전환하는 것입니다.

여기에서


CFRunLoop의 가장 중요한 기능은 CFRunLoopModes입니다. CFRunLoop은 “Run Loop Sources”시스템과 함께 작동합니다. 소스는 하나 또는 여러 모드의 런 루프에 등록되며 런 루프 자체는 주어진 모드에서 실행되도록 만들어집니다. 이벤트가 소스에 도착하면 소스 모드가 실행 루프 전류 모드와 일치하는 경우에만 실행 루프에 의해 처리됩니다.

여기에서


답변