오늘은 미루고 미룬 런 루프 모드에 관해 정리해 보고자 한다.
조금 심화적인 내용을 다룰 것이기 때문에 Run loop의 개념 정도는 알고 있어야 읽기 수월하다.
Run loop의 기본적인 개념을 정리한 글은 여기
그럼 시작
RunLoop.Mode?
Run Loop 모드는 루프를 통과하는 동안 특정 소스만 모니터링하기 위해 사용한다.
즉, 모드를 사용하여 루프를 통과하는 동안 원치 않는 소스에 대한 이벤트를 필터링할 수 있다.
예를 들어 마우스나 키보드와 같은 입력 소스에 대한 이벤트만 처리하고 싶을 때나,
입력 소스와 타이머 소스 모두 처리하고 싶을 때 특정 모드로 설정하여 제어할 수가 있다.
주의: 모드는 이벤트가 발생하는 소스를 기준으로 구별하기 위함이지, 이벤트의 타입을 구별하는 용도는 아님
예를 들어 전체 마우스 이벤트 중에서 마우스 클릭 이벤트만 필터링한다던지 등의 기능은 모드만 써서 구현할 수 없다.
Mode의 종류
모드는 루프 실행 시 설정할 수 있고, 총 다섯 가지 종류가 있다.
default
기본 모드는 대부분의 작업에 사용되는 모드이다.
대부분의 경우 이 모드를 사용하여 런 루프를 시작하고 입력 소스를 구성한다.
common
여러 Mode의 집합. 해당 옵션으로 추가된 이벤트 소스는 이 모드에 속한 모든 모드에 속하게 된다.
기본적으로 Cocoa는 default, modal, eventTracking(혹은 tracking) 모드가 속하게 되고,
Core Foundation은 default 모드만 속해있다.
eventTracking
특정 이벤트 루프 중에 다른 이벤트 발생을 막아야 할 때 사용한다.
modalPanel
Modal Panel에서 발생한 이벤트만 처리한다.
tracking
컨트롤을 추적하고 있는 상황에서 사용한다.
사용 예제
다음은 메인 런 루프에 common 모드로 타이머를 등록하는 예제이다.
lazy var timer: Timer = {
Timer.scheduledTimer(withTimeInterval: 2, repeats: true) { _ in
print("Running run loop")
}
}()
DispatchQueue.main.async {
RunLoop.current.add(timer, forMode: .common) // set mode common
}
add(_:forMode:)는 특정 모드로 특정 타이머를 등록하는 메서드이다.
UIScrollView에서 스크롤 시, 타이머가 동작하지 않는 문제
실제로 scrollView에서 스크롤 시, 타이머가 동작하지 않는데 이 문제를 mode를 사용해서 해결할 수 있다.
다음은 메인 런 루프에서 타이머를 동작시키는 코드이다.
타이머가 동작하다가 스크롤하는 동안에는 타이머가 동작하지 않는 것을 볼 수 있다.
타이머가 동작하지 않는 이유는
메인 런 루프의 초기 상태는 default 모드이다.
스크롤뷰에서 스크롤 시 사용자 상호 작용을 감지하기 위해 Timer 이벤트가 발생하는데,
스크롤(사용자 상호 작용)이 감지되면
루프는 tracking(=컨트롤을 추적하는 mode) 모드로 변경되어, 타이머 소스를 모니터링하지 않게 된다.
그렇기 때문에 타이머가 동작하지 않는 것
스크롤이 끝나면 다시 default 모드가 되고 타이머는 정상 작동된다.
스크롤 시에도 타이머가 동작하게 만들기 위해서는
루프에 타이머를 등록할 때 tracking 또는 common 모드로 지정해주면 된다.
참고
https://developer.apple.com/documentation/foundation/timer
'Study > Swift' 카테고리의 다른 글
[Swift] 고차함수(2) - filter, reduce (0) | 2022.09.26 |
---|---|
[Swift] 고차함수(1) - map, flatMap, compactMap (0) | 2022.09.18 |
[Swift] Run Loop (0) | 2022.07.25 |
[Swift] Initializer 심화 (2) (0) | 2022.07.20 |
[Swift] Initializer 심화 (1) (0) | 2022.07.19 |