[iOS] - RunLoop 개념


Run Loops

  • Thread와 연관된 근본적인 infrastructure의 일부로, 작업을 스케줄링하거나 들어오는 이벤트들을 조합하는데 사용하는 이벤트 처리 loop
  • Thread 가 진입하고, 들어오는 이벤트에 대해 대응하는 event handler 들을 실행하기 위해 사용하는 loop. Loop 내부에서는 이벤트들을 받고 설치된 handler 들을 호출하는 이벤트 처리 코드를 실행하기 위해 run loop 객체를 사용한다.
  • 목적 : 작업이 있을 때 thread에서 수행하기. 수행해야 하는 작업이 있을 때 thread를 일하게 하고 작업이 없을 때 thread를 잠자게 한다.

Run loop 가 하는 관리 작업은 완전히 자동적으로 이루어지지는 않는다. 개발자가 적절한 시점에 thread 에서 run loop 를 시작하게 하고, 들어오는 이벤트에 반응하는 코드를 직접 작성해야 한다. Cocoa 와 Core Foundation 은 thread 의 run loop를 구성하고 관리하기 위해 run loop 객체들을 제공한다. 앱에서 run loop 객체들을 명시적으로 생성할 필요는 없다. Main thread 를 포함한 모든 thread들이 각자 run loop 객체를 가지고 있다. 오직 secondary thread 들만 run loop 를 명시적으로 실행해야 한다. 앱 프레임워크는 앱 startup 프로세스 중에 자동으로 main thread 에서 run loop 를 set up 하고 실행한다.

Sources

Run Loop 는 이벤트를 source 들에게서 받는다. Source에는 두 종류가 있고, 모두 이벤트가 왔을 때 이를 처리하기 위한 application-specific handler 루틴을 사용한다.

 Input SourceTimer Source
전달하는 이벤트다른 thread나 다른 앱에서 전달한 비동기 이벤트특정 시간에 발생, 혹은 특정 주기마다 반복되는 동기 이벤트
Run loop exitO (비동기 이벤트가 일치하는 handler에 전달되고 thread의 연관된 RunLoop 객체의 runUntilDate: 메서드를 호출해서 exit)X (이벤트가 handler에 전달되지만 run loop 가 exit 하지는 않는다.)

image

Input Sources

Thread 에 이벤트를 비동기적으로 전달한다. Source 에 두 종류가 있는데 둘 중 무엇인지는 중요하지 않다. 둘의 차이는 어떻게 시그널되는지다.

  1. Port-based input source : 앱의 Mach port 를 모니터링한다. 커널에 의해 자동으로 시그널 된다.
  2. Custom input source : Custom source 를 모니터링 한다. 다른 thread 에 의해 수동적으로 시그널 된다.

Mode

모니터 되어야 하는 input source, timer 들과 notify 받아야 하는 run loop observer 들의 집합. Run loop 가 실행되도록 정해진 모드와 관련 있는 source 들만 모니터링 되고 이벤트를 전달할 수 있고, 관련 있는 observer 들만 notify 받을 수 있다.

  • 이름 : 모드는 이름(문자열)으로 정의된다. Cocoa, Core Foundation은 기본 모드와 자주 사용되는 모드들을 문자열로 정의해 놨고, 개발자가 임의의 문자열로 이름을 정해 커스텀 모드를 정의할 수 있다. 생성한 모드에는 무조건 하나 이상의 source 나 observer 를 추가해야 한다.
  • 필터링 : 모드를 사용해서 이벤트를 받고 싶지 않은 source 들을 거를 수 있다. 기본적으로는 시스템에서 정의된 default 모드에서 run loop 를 실행한다. Secondary thread 에서는 수행 시간이 중요한 작업들에서 중요도가 낮은 이벤트를 받지 않기 위해 커스텀 모드를 사용할 수 있다.

Run Loop를 사용해야 할 때

Secondary thread 를 생성할 때만 명시적으로 run loop 를 실행한다.

  • Main thread : Main thread 의 run loop 는 infrastructure 의 매우 중요한 부분을 담당하고 있기 때문에 프레임워크는 main application loop 을 실행하고 자동으로 시작하게 하는 코드를 이미 갖고 있다. UIApplicationrun 메서드는 startup 과정의 일부로서 main loop 을 실행한다.
  • Secondary thread : Run loop 이 필요한지 결정해서 직접 구성하고 시작해야 한다. 모든 경우에 thread 의 run loop 을 시작할 필요는 없다. 만약 thread 가 수행 시간이 길고 미리 결과가 결정된 작업을 수행한다면 run loop 를 시작할 필요가 없다. Run loop 는 thread 가 이벤트를 많이 받으며 상호작용 할 필요가 있는 상황에서 사용되는 것이 좋다.

다음의 경우 run loop 를 시작해야 한다.

  • 다른 thread 와 소통하기 위해 port 나 커스텀 input source 를 사용해야 할 때
  • Thread 에서 타이머를 사용해야 할 때
  • Cocoa application 의 performSelector... 메서드를 사용해야 할 때
  • 주기적인 작업을 수행하기 위해 thread 를 가지고 작업을 계속 해야 할 때

Thread safety

Thread safety 는 run loop 에서 사용하는 API 에 따라 다르다. Core Foundation 의 함수들은 일반적으로 Thread-safe 하지만 run loop 의 설정을 바꾸는 작업을 할 때는 그 run loop 를 가진 thread 에서 하는 것이 좋다.

RunLoop 클래스는 일반적으로 thread-safe하지 않기 때문에 현재 thread 문맥 내에서만 RunLoop 의 메서드를 호출해야 한다. 다른 thread 의 run loop 에 input source 나 timer 를 추가하면 크래시가 발생하거나 예상하지 못한 동작을 할 수 있다고 한다.