본문 바로가기
iOS/설명

[iOS] RunLoop

by Sky Titan 2024. 11. 10.
728x90

https://babbab2.tistory.com/68

iOS) 런 루프(RunLoop) 이해하기

안녕하세요 :) 소들입니다 오늘은 RunLoop라는 것에대해 공부를 해볼 건데여 음... 내용이 좀 어려울 수도 있어여!! 저도 오랜만에 다뤄서 완전히 이해하고 쓰는 내용이 아니라... (한 1년 전에 공부

babbab2.tistory.com

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

RunLoop | Apple Developer Documentation

The programmatic interface to objects that manage input sources.

developer.apple.com

RunLoop

  • RunLoop은 window system의 마우스, 키보드나 port에서 오는 event들을 처리하는 object이다.
  • 또한 Timer event도 처리한다.
    • RunLoop입장에선 Timer는 input이 아니지만 특별한 타입으로써 취급한다.
  • System은 main thread를 포함해서 기본적으로 모든 thread마다 RunLoop을 생성한다.
    • 다만 main thread를 제외하고 RunLoop이 처음부터 생성되어있는 것은 아니고 RunLoop.current로 현재 스레드의 RunLoop에 접근시도 시 RunLoop이 존재하지 않으면 생성한다.
    • Main thread의 RunLoop은 앱 실행 시, UIApplicationMain()함수 내부에서 초기화 된다.
  • 주의해야될 건 RunLoop은 Thread safety하지 않기 때문에 반드시 현재 thread의 context내에서만 사용해야한다.

 
 

Main RunLoop

Main RunLoop의 동작구조
  • Main RunLoop은 앱 실행 시 생성과 loop의 실행이 자동적으로 진행된다.
  • Device에서 일어나는 user의 이벤트를 OS, Port를 거쳐서 Event Queue에 받은 뒤 UIApplication을 시작으로하는 UIResponder chain에 넘겨줘서 처리하도록 한다.

 

Worker thread에서 Timer가 동작하지 않는 이유

    override func viewDidLoad() {
        super.viewDidLoad()
        DispatchQueue.global().async(execute: {
            Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true, block: { _ in
                print("timer")
            })
        })
    }

 위 코드를 실행 시 Timer의 동작은 제대로 실행되지 않는다.
그 이유는 Worker thread의 RunLoop은 현재 생성되어있지도 않고, loop가 돌고 있는 상황도 아니기 때문

Event를 받아들이지 않음

때문에 아래와 같이 명시적으로 run을 호출해줘야 Input source로부터 Event를 받아들이고 처리하기 시작한다.

    override func viewDidLoad() {
        super.viewDidLoad()
        DispatchQueue.global().async(execute: {
            Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true, block: { _ in
                print("timer")
            })
            RunLoop.current.run()
        })
    }

 

Appendix

Timer() vs Timer.scheduledTimer()

Timer가 RunLoop에 붙어있지 않은 상태

Timer()는 타이머 객체를 생성만하고 RunLoop에 붙이지는 않는다. 때문에 RunLoop에 붙이기 전까진 Timer가 동작하지 않는다.

때문에 Timer() 사용 시 아래와 같이 current RunLoop에 명시적으로 Timer를 추가해줘야한다.

    override func viewDidLoad() {
        super.viewDidLoad()
        DispatchQueue.global().async(execute: {
            let timer = Timer(timeInterval: 0.5, repeats: true, block: { _ in
                print("timer")
            })
            RunLoop.current.add(timer, forMode: .common)
            RunLoop.current.run()
        })
    }

 
반면 scheduledTimer는 Timer 객체 생성 후 current RunLoop에 default mode로 추가하는 작업까지 해준다. 때문에 add()함수를 호출해서 timer를 명시적으로 붙여주지 않아도 Timer가 동작한다.

728x90

'iOS > 설명' 카테고리의 다른 글

[iOS] '==' vs '==='  (0) 2024.03.17
[iOS] OOP와 POP는 어떤 경우에 써야 할까 (고찰)  (0) 2024.03.17
[iOS] High performance based drawing  (0) 2024.02.24
[iOS] Mirror Struct  (0) 2024.02.24
[iOS] iOS Webview에서 텍스트 복사하는법  (0) 2023.07.15

댓글