IOS

[IOS] 스크롤 중 Timer가 동작하지 않았던 이슈와 해결방법

이 글을 이해하기 위해서는 먼저 Timer와 RunLoop에 대한 이해가 필요하다. 

 

Timer와 RunLoop에 대하여 간략하게 정리한 글

 https://lietenant-k.tistory.com/29?category=999190)


팀 프로젝트를 진행하다가 Timer를 활용하여 카운트다운 기능을 구현하려고 했다.

 

countDown 메서드 내부에서 Main RunLoop에 Timer를 추가하고 1초 간격으로 타이머를 발동시켜서 해당 코드 블럭을 호출하게 했다. 

var time = 10
let label = UILabel()

func countDown(){
        
        let timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { 
        	[unowned self] timer in
            
            	if time < 0 {
                	timer.invalidate()
                	return
            	}	
            
            	label.text = "\(Int(time))"
                time -= 1
        }
}

timer의 코드 블록은 호출될 때 마다 time 변수에 저장된 값을 1씩 감소시켜 Label에 표시한다.

만약 time에 저장된 값이 0보다 작을 경우 타이머를 현재 RunLoop에서 해제하도록 했다.

여기까지는 문제없이 우리가 예상했던 결과를 얻을 수 있었다.

 

그런데 ScrollView(대표적으로 TableView, CollectionView)를 조작하는 도중엔

코드 블록이 실행되지 않는 문제가 발생했다.

 

나는 Main RunLoop에서 사용자의 스크롤 이벤트(input source)를 처리하느라

Timer의 이벤트를 처리하지 못해서 그런 것이라고 생각했다. 

 

그래서 처음엔 Timer를 메인 스레드가 아닌 백그라운드 스레드의 RunLoop에 추가하려고 했으나,

결국 UI를 수정하는 작업은 메인 스레드에서 해야 했기에 도움이 되는 방법이 아니었다. 

 

하지만 구글링으로 쉽게 해결방법을 찾을 수 있었다.

결론은 Main RunLoop의 common Mode에 Timer를 추가 해주면 된다.

 

RunLoop에는 여러 modes가 존재하고 다수의 모드에 Timer를 추가할 수 있다.

모드를 지정하지 않을 경우 default 모드에 Timer가 추가된다.

 

mode는 쉽게 말하자면 특정 이벤트 소스의 이벤트만을 처리하는 필터라고 생각하면 된다.

특히 common 모드는 여러 모드가 속해있는 모드로서,

common 모드에 추가된 이벤트 소스의 이벤트를 이 모드에 속한 모든 모드에서 처리가 가능하다. 

 

따라서 결론적으로 스크롤 이벤트를 처리하는 Run Loop의 특정 모드에서

Timer의 이벤트도 처리할 수 있도록 아래의 코드를 추가해주면 스크롤 시 Timer가 정상적으로 작동된다.

RunLoop.current.add(timer, forMode: .common)

 


참고 문서 : https://khorbushko.github.io/article/2020/11/29/runloop-in-depth.html

 

RunLoop in details

Often we can hear such terms as RunLoop, MainLoop, or EventLoop. But do we know how it works? And what responsibilities it has?

khorbushko.github.io

https://jcsoohwancho.github.io/2019-09-01-스레드-프로그래밍(2)-RunLoop/ 

 

스레드 프로그래밍(2) - RunLoop

지난 포스트에서 스레드의 기본에 대해서 알아보았습니다. 이번에는 스레드가 외부 이벤트를 받아들이는 방법에 대해서 알아보겠습니다. 이 포스트는 지난 포스트와 마찬가지로 다음 가이드를

jcsoohwancho.github.io