[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 Source | Timer Source | |
---|---|---|
전달하는 이벤트 | 다른 thread나 다른 앱에서 전달한 비동기 이벤트 | 특정 시간에 발생, 혹은 특정 주기마다 반복되는 동기 이벤트 |
Run loop exit | O (비동기 이벤트가 일치하는 handler에 전달되고 thread의 연관된 RunLoop 객체의 runUntilDate: 메서드를 호출해서 exit) | X (이벤트가 handler에 전달되지만 run loop 가 exit 하지는 않는다.) |
Input Sources
Thread 에 이벤트를 비동기적으로 전달한다. Source 에 두 종류가 있는데 둘 중 무엇인지는 중요하지 않다. 둘의 차이는 어떻게 시그널되는지다.
- Port-based input source : 앱의 Mach port 를 모니터링한다. 커널에 의해 자동으로 시그널 된다.
- 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 을 실행하고 자동으로 시작하게 하는 코드를 이미 갖고 있다.
UIApplication
의run
메서드는 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 를 추가하면 크래시가 발생하거나 예상하지 못한 동작을 할 수 있다고 한다.
- 참고
- https://developer.apple.com/documentation/foundation/runloop
- https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html