본문 바로가기

카테고리 없음

NSRunloop

NSRunloop ?

윈도우 시스템으로 부터 오는 마우스, 키보드 이벤트 또는 NSPort입력 소스를 처리하는 객체입니다.

런루프는 스레드와 관련하여 근본적인 인프라의 일부 입니다.

런루프는 작업들을 스케줄링하거나, 입력이벤트들과 협력하기 위해 사용됩니다. 런루프의 목적은 수행해야할 작업이 있다면 스레드를 바쁜 상태로 놓고, 작업이 없다면 스레드를 휴식상태로 만들어 놓는데에 있습니다.

 

Run loop Management는 완전히 자동이 아닙니다. 

스레드의 코드가 적당한 때에 런루프를 시작할수 있고, incoming event에 대해 응답할 수 있도록 스레드 코드를 작성해야만 할 것 입니다.

런루프를 명시적으로 만들 필요는 없습니다.

 

어플리케이션의 메인스레드를 포함하여 각 스레드들은 관련된 런루프 객체를 가지고 있기 때문입니다. 하지만 메인스레드가 아닌 이외의 스레드들을 실행 시킬땐 그 스레드들의 런루프를 명시적으로 run 시켜야 합니다.

어플리케이션의 실행 프로세스의 일부로서 앱 프레임워크는 자동적으로 메인스레드의 런루프를 실행, 세팅시킵니다.

 

 

 

위 그림에서, input source는 비동기적으로 핸들러에게 이벤트를 전달한다. 그리고 runUntilDate 메서드를 실행시켜 지정한 시간대까지 런루프를 실행시킨다. (종료시킬 수 있다는 것이다.)

반면 Timer는 핸들러에게 이벤트를 전달할 수 있지만 런루프가 종료되도록 하지는 않는다.

 

 

RunLoop Modes

모니터링되는 이벤트 소스(input source)와, 알림을 받는 RunLoop 옵저버의 집합.

런루프를 실행할때 마다, 명시적,암시적으로 어떤 특정 모드로 실행시킬지 지정하게 된다.

런루프를 통과하는동안, 특정(지정한 모드) 모드와 관련된 소스만이 모니터링되고, 이벤트를 전달할 수 있다. ( 마찬가지로 해당모드와 관련된 옵저버만이 런루프의 알림을 받을 수 있다.) 

 

RunLoop Mode를 사용하여 런루프를 통과하는 특정 이벤트들중, 원치않는 input source로 부터의 이벤트를 필터링한다.

 

모드는 이벤트유형이 아닌 이벤트 출처에 따라 구분된다.
예를들어, 모드를 사용하여 마우스다운 이벤트만 일치시키거나 키보드 이벤트만 일치시킬 수 없다.
모드를 사용하여 다른 포트들을 수신하거나, 타이머를 일시적으로 중단시키거나, 
현재 모니터링중인 소스 및 런루프 옵저버를 변경할 수 있다.

 

Mode 이름  설명
Default RunLoop.Mode.default(Cocoa)
kCFRunLoopDefaultMode(Core Foundation)
대부분의 연산에 대한 기본모드
Modal NSModalPanelRunLoopMode (Cocoa) Modal Panel에서 발생한 이벤트만 처리합니다.
macOS에서만 사용 가능합니다.
Event Tracking RunLoop.Mode.eventTracking(Cocoa) 사용자 인터페이스를 추적하는 종류의 이벤트 중에 (마우스 드래깅과 같은 이벤트) 다른 이벤트의 발생을 막는다.
Common modes  RunLoop.Mode.common(Cocoa)
kCFRunLoopCommonModes(Core Foundation)
여러 Mode의 집합입니다. 이 옵션으로 추가된 이벤트 소스나 옵저버는 common 모드에 속한 모든 모드에 속하게 됩니다.
기본 값으로 Cocoa는 default, modal, eventTracking(혹은 tracking) 모드가 속하게 되고, Core Foundation은 default모드만 속해있습니다. 여기에 새로운 모드를 추가하려면 CFRunLoopAddCommonMode(::) 함수를 사용하면 됩니다. (제거 기능은 없습니다.)

 

Input Source

input source는 스레드에 비동기적으로 이벤트를 전달한다. 이벤트의 소스는 input source의 타입에 따라 결정된다.

보통 두가지인데,

- Port based : 앱의 Mach 포트를 모니터링하는 input source

- Custom input source: 커스텀 이벤트의 소스를 모니터링하는 input source

 

하지만 런루프에 관한 한, input source가 어떤 종류인지는 꼭 중요하지는 않다,

시스템은 일반적으로 그대로 사용할 수 있는 두 가지 유형의 입력 소스를 구현한다. 두 소스의 유일한 차이점은 신호를 보내는 방법이기 떄문이다.
Port based는 커널에 의해 신호가 보내지고, custom은 또다른 스레드로 부터 신호가 보내진다.
 
input source를 만들때, 하나이상의 모드에 할당하게 된다. 모드는 주어진 순간에 모니터링되는 input source에 대해 영향을 미친다.
입력 소스가 현재 모니터링되는 모드가 아니면 런 루프가 올바른 모드에서 실행될 때까지 입력 소스가 생성하는 모든 이벤트가 유지된다.
 

Timer Source

Timer Source는 미래의 미리 설정된 시간에 스레드에 동기적으로 이벤트를 전달한다.

타이머는 스레드가 자신에게 무언가를 하도록 알리는 방법이다. 예를 들어, 검색 필드는 타이머를 사용하여 사용자의 연속적인 키 입력 사이에 일정 시간이 지나면 자동 검색을 시작할 수 있다. 이 지연 시간을 사용하면 사용자가 검색을 시작하기 전에 원하는 검색 문자열을 최대한 많이 입력할 수 있다.

 

Run Loop Observers

적절한 비동기 또는 동기 이벤트가 발생할 때 발생하는 소스와 달리 Run Loop Observer는 런 루프 자체가 실행되는 동안 특정 지점(상황)에서 발생한다.

Run Loop Observer를 사용하여 스레드가 주어진 이벤트를 처리하도록 준비하거나 스레드가 절전 모드로 전환되기 전에 준비할 수 있다.

Observer를 적용할 수 있는 지점은 다음과 같다.

- RunLoop가 시작할 때

- Timer 이벤트를 시작하기 직전

- input 이벤트를 처리하기 직전

- 잠자기 상태로 들어가기 직전

- 어떤 이벤트로 인해 스레드가 깨어나서 그 이벤트를 처리하기 직전

- RunLoop가 종료될 떄

 

RunLoop에 옵저버를 붙이기 위해서는 CoreFoundation의 CFRunLoopObserver 인스턴스를 만들어야 한다.

 

The Run Loop Sequence of Events

실행할 때마다 스레드의 런 루프는 보류 중인 이벤트를 처리하고 연결된 관찰자에 대한 알림을 생성한다. 이 작업을 수행하는 순서는 매우 구체적이며 다음과 같다.

 

  1. observers에게 RunLoop가 시작한다고 알린다.
  2. observers에게 Timer 이벤트가 발생할 것을 알린다.
  3. observers에게 port-based가 아닌 input source 이벤트가 발생할 것을 알린다.
  4. 실행할 준비가 되어있는 port-based가 아닌 input source 이벤트를 발생시킨다.
  5. 실행할 준비가 되어있는 port-based input source가 있다면 , 해당 이벤트를 즉시 처리한 후. 9번 단계로 간다.
  6. observers에게 스레드가 곧 잠들것을 알린다.
  7. 다음과 같은 이벤트들이 발생하때 까지 스레드는 잠자기 상태가 된다.
    • port-based input source 이벤트가 들어왔을 때.
    • Timer가 시작되었을때.
    • RunLoop가 타임아웃 되었을 때.
    • RunLoop가 명시적으로 깨워졌을 때
  8. observers에게 스레드가 깨어났음을 알린다.
  9. 남은 이벤트들을 처리한다.
    • 사용자 지정 Timer 이벤트가 발생할 경우, 타이머 이벤트를 처리하고 루프를 다시 시작한다. 2번으로 돌아간다.
    • input 이벤트가 발생한 경우, 이벤트가 전달됩니다.
    • RunLoop가 명시적으로 깨어났는데, 아직 타임아웃 되지 않은 경우, 루프를 다시 시작한다. 2번으로 돌아간다.
  10. observer에게 RunLoop가 종료됨을 알린다.

 

 

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

 

Run Loops

Run Loops Run loops are part of the fundamental infrastructure associated with threads. A run loop is an event processing loop that you use to schedule work and coordinate the receipt of incoming events. The purpose of a run loop is to keep your thread bus

developer.apple.com

https://jcsoohwancho.github.io/2019-09-01-%EC%8A%A4%EB%A0%88%EB%93%9C-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D(2)-RunLoop/