User Event & MainRunLoop

김동현·2022년 9월 9일
0

iOS

목록 보기
4/13


TableView에서 스크롤 동작을 진행 할 때마다,
기존에 진행되고 있었던 Timer의 로직이 수행되지 않는 이슈를 만나게 되었습니다.
트러블 슈팅 도중에 RunLoop와 연관이 있었다는 것을 알게 되었으며,
이슈 해결 방법과 Runloop에 대해 알아보는 시간을 가졌으면 해서 글을 작성해보려 합니다.

이야기를 시작하기 앞서 AppLifeCycle에 대해서 알아보겠습니다.
MainRunLoop의 생성을 엿 볼 수 있기 때문인데요!
AppLifeCycle의 순서는 아래와 같습니다.

  1. 사용자가 앱의 아이콘을 터치했을 때
  2. main이라는 함수의 호출이 진행됩니다.(UIKit에서 main 함수를 관리 하기 때문에 개발자는 따로 main에 관여하지 않아도 됩니다.)
  3. 그리고 main 함수는 UIApplicationMain 함수를 호출 시킵니다.
  4. 이 과정을 통해서 앱의 본체에 해당하는 UIApplication 객체가 생성이 됩니다.
  5. nib 파일, Info.plist 파일의 데이타를 로드하게 되고
  6. AppDelegate 객체를 만든 후 UIApplication 객체와 연결 시키며, RunLoop를 생성하게 됩니다.
  7. 실행 완료를 앞두고 UIApplication 객체는 AppDelegate 객체에게 didFinishLaunchingWithOptions 메서드를 호출 시킵니다.


MainRunLoop


위 AppLifeCycle을 기반으로 앱 시작 시 Main Run Loop가 생성된다는 것을 확인하였습니다.
그렇다면 여기서 Main Run Loop란 무엇일까요?
사용자 관련 이벤트들을 받는 순서대로 처리하는 담당자라고 말할 수 있겠는데요!
이미지와 함께 Main Run Loop가 사용자의 이벤트에 대해 어떻게 동작하는지 알아보겠습니다.
사용자의 인터렉션이 발생하면, 그 액션에 해당하는 이벤트가 시스템에 의해 생성되고,
UIKit에서 생성한 port를 통해 앱에 전달 됩니다.
전달된 이벤트들은 queue에 보관되고 하나씩 Main Run Loop로 전달되어 처리됩니다.

여기까지 AppLifeCycle,
그리고 해당 Cycle에서 생성된 MainRunLoop
해당 loop가 수행하는 역할이 무엇인지에 대해 알아봤습니다.

이제 이슈를 설명하기에 충분한 내용을 설명드린 것 같은데요!
경험했던 이슈 내용은 이러했습니다.

상단에 View가 있었고 하단에는 TableView가 위치해 있었습니다.
그리고 상단 View에는 Timer의 호출로 인하여 View의 update가 지속적으로 발생하고 있는 상황이였습니다.
문제는 TableView의 scroll 이벤트를 진행했을 때
Timer의 selector 메소드가 호출이 되지 않는 상황이 생겨버리는 것이였습니다..

원인은 TableView에 scroll 동작이 발생했을 때
RunLoop는 TableView의 scroll에 대한 이벤트를 처리했었고,
Timer의 호출로 인한 View의 업데이트는
TableView의 Scroll 동작으로 인하여 뒷전으로 밀려 버리는 상황이 되버렸기 때문에 발생했던 것으로 확인되었습니다.🥲

그리고 Stackoverflow에서 이와 동일한 에피소드를 간간히 찾아 볼 수 있었습니다.
스택오버플로우 답변 링크
RunLoop를 통해 해결한 사례였는데 저도 동일하게 적용하여 해결하였습니다.

코드를 보자면 이러합니다.

self.updateTimer = Timer.scheduledTimer(
								timeInterval:1.0, 
                                target: self, 
                                selector: Selector(("updateFunction")), 
                                userInfo: nil, repeats: true
                                )
RunLoop.current.add(self.updateTimer, forMode: RunLoopMode.common)


RunLoop의 current에 접근하게 되면 현재 Thread의 실행 루프를 반환하게 되고
add 라는 메소드를 사용할 수 있게 됩니다.
그리고 첫번째 인자에 문제가 되었던 Timer를 넣고
두번째 인자에는 .common으로 호출 하게 되면,
Timer가 현재 Thread의 실행 루프에 추가되어서,
UI와 상호작용하는 동안 타이머가 효과적으로 실행될 수 있도록 합니다.
TableView의 스크롤 동작 여부와는 무관하게
Timer의 이벤트로 인한 View의 업데이트도 정상적으로 진행되는 것을 확인할 수 있었습니다.🙌

profile
iOS 개발자 김동현입니다 :)

0개의 댓글