iOS/iOS이모저모

[iOS] 왜 메인스레드에서만 UI 업데이트를 할까?

최지철 2024. 5. 28. 18:02
728x90
반응형

서론

  • iOS개발을 하다보면 UI 업데이트 관련 로직은 main thread에서 작업을 해야한다는것을 알것이다. 비동기 작업을 하면서 UI업데이트 시, 당연스럽게 메인스레드에 작업을 지정하며 넘어갔다. 문뜩 왜 메인스레드에서만 UI 작업을 해야할까? 라는 의문이 들기 시작했다.
  • 메인스레드보다 백그라운드 스레드에서 하는게 더 좋지 않을까? 

짚고 넘어가야할 개념 Thread-safe

멀티 스레드 프로그래밍에서 일반적으로 어떤 함수나 변수, 혹은 객체가 여러 스레드로부터 “동시에” 접근이 이루어져도 프로그램의 실행에 문제가 없음을 의미한다.

UIKit은 기본적으로 Thread Safe하지 않다. UIKit과 같은 매우 큰 프레임워크에서의 모든 속성들을 Thread-Safe 하게 설계하는 것은 엄청 비현실적이기에 Serial Queue에서 처리함으로써 Thread Safe 않음으로 생기는 문제들을 해결할 수 있다.

 

그렇다면 왜 UIKit과 같은 큰 프레임워크의 모든 속성들을 Thread-Safe 설계 하는 것이 엄청 비현실적일까?

  • Thread Safety를 보장하기 위해서는 추가적인 동기화 메커니즘이 필요한데, 이는 각 속성 접근 시마다 락(lock)을 사용하거나, 동기화 큐를 사용해야 함을 의미한다. 이러한 동기화는 성능 오버헤드를 유발하여, 특히 UI와 같이 높은 응답성을 요구하는 작업에서는 캐시의 일관성, 락경쟁, 데드락등의 많은 문제를 야기할 가능성이 높기 때문이다.

 

Thread-safe하지 않는 UIKit

  • 앞서 Thread-safe로 모든 속성들을 설계하는것은 위험하다는것을 알았다. 그렇다면, Apple이 의도적으로 Thread - safe하지 않게 설계한것일까?
  • 그렇다. UIKit이 Thread-Safe 하지 않은것, UI를 메인스레드에서 처리하는것은 Apple의 의도적인 디자인 결정이다.

 

그렇다면, UIKit을 통채로 백그라운드 스레드에서 돌아가게 할 수 는 없을까?

  • 결론을 먼저 말하자면, 불가능하다. 그 이유는 iOS에서의 렌더링과정을 통해 알 수 있다. 

결말을 알지만,  상상해보자 마치 소설책을 뒤에서 부터 읽듯이...

RunLoop 와 View Drawing Cycle

  • 우리가 알고 있듯이, UIApplication은 메인 스레드에서 Main RunLoop를 호출해, RunLoop 을 초기화하고, 그것은 유저 인터렉티브 등과 같은 앱의 수명 동안 대부분의 사용자 이벤트를 처리한다. 이런 RunLoop는 사용자 이벤트를 가능한 빨리 응답 할 수 있도록 지속적으 로 이벤트 처리를 하고 절전 시키는 일 등을 처리하는 지속적 반복 과정에 있으며. 화면 을 새로 고칠 수 있는 이유는 'Main Runloop'가 동작 중이기 때문이다.

     또한 모든 뷰의 변경 사항은 즉시 변경되지 않으며, 현재의 RunLoop의 끝에서 다시 그려 (redraw)집니다. 이를 해 앱이 모든 뷰에 대한 모든 변경 사항을 처리를 보장할 수 있으며 모든 변경 사항이 동시에 성화 수 있다. 이것을 "View Drawing Cycle"이라 한다.

     
     UIKit을 백그라운드 스레드에서 UI를 업데이트한다고 가정해보자. 각 스레드마다 자체 RunLoop가 있기 때문에 스마트을 때, 레이아을 새로 고야 할 때 문제가 발생할 수에 없다. 모든 변경 사항을 동시에 적용 할 수 없으로 스마트전시키고 나서 개의 뷰는 전하지 않은 것을 보게 수도 있다. 그리고 UIKit이 메인 스레드에 없기 때문에 Main RunLoop의 사용자 이벤트가 디스플레이와 동기화되지 않는다.

 

그렇다면, 전체 UIApplication의 사용자 이벤트 메커니즘을 백그라운드 스레드로 리팩터링하면, 스레드의 동기적 인 문제를 처리 할 수 있지 않을까?

  • 불가능하다. 그 이유는 iOS 렌더링 과정에서 알 수 있다.
  • iOS에서는 모든 뷰가 UIKit이 아닌 Core Animation Framework에 의해 표시되고 보여지기 때문이다.



iOS 렌더링 과정

  • UIKit : 모든 종류의 구성 요소를 포함하고 사용자 이벤트를 처리하며 렌더링 코드를 포함 하지 않음
  • Core Animation : 모든 뷰를 그리거나, 디스플레이(표시)하고 애니메이션을 담당
  • OpenGL ES : 2D 및 3D 렌더링 서버를 제공함 
  • Core Graphics : 2D 렌더링 서버를 제공함
  • 그래픽 하드웨어 : GPU

 

결론

iOS에서는 모든 뷰가 UIKit이 아닌 Core Animation Framework에 의해 표시되고 보여진다.
이와 함께 메인 스레드에서 UI를 업데이트하는 이유는 UIKit이 스레드에 안전하지 않기 때문이다.
즉, UIKit은 메인 스레드에서만 안전하게 사용할 수 있도록 설계되어 있어, UI 업데이트가 메인 스레드에서 이루어지지 않으면 예기치 않은 동작이나 충돌이 발생할 수 있다. 따라서, 모든 UI 작업은 메인 스레드에서 수행하여 안정적이고 일관된 사용자 경험을 제공한다.

 

[참고]https://medium.com/@duwei199714/ios-why-the-ui-need-to-be-updated-on-main-thread-fd0fef070e7f

728x90
반응형