프로그래밍모바일 개발자

GCD(Grand Central Dispatch) 및 DispatchQueue의 작동 원리를 설명하고, 비동기 코드를 올바르게 작성하는 방법과 멀티스레딩 작업 시 겪을 수 있는 문제점은 무엇인지 설명하세요.

Hintsage AI 어시스턴트로 면접 통과

답변.

질문의 역사

Grand Central Dispatch(GCD)는 2009년 iOS와 macOS에 도입된 저수준 시스템으로, 큐(DispatchQueue)를 기반으로 비동기 코드를 구성하는 데 사용됩니다. GCD는 스레드 관리를 수동으로 하는 것보다 훨씬 간결하며, 안전한 작업 실행, 동기화 및 편리한 API를 제공합니다.

문제

비동기성과 멀티스레딩은 전통적으로 많은 문제의 원인입니다: 데이터 경합, 교착 상태, UI의 잠재적 블로킹 및 복잡한 크래시. 큐를 잘못 사용하거나 메인 스레드가 아닌 스레드에서 UI에 접근하려고 하면 버그가 발생할 수 있습니다.

해결책

Swift는 쉽게 백그라운드 작업을 만들고, 백그라운드에서 메인 스레드로 안전하게 돌아와 UI를 업데이트할 수 있게 합니다. 비동기 작업에는 DispatchQueue를 사용하고, 비동기 작업 세트를 완료할 때까지 기다려야 할 경우 DispatchGroup을 사용하세요.

코드 예:

let backgroundQueue = DispatchQueue(label: "background", qos: .background) backgroundQueue.async { // 백그라운드 스레드에서 실행됩니다. let image = downloadImage() DispatchQueue.main.async { // 안전한 UI 업데이트 imageView.image = image } }

주요 특징:

  • DispatchQueue.async는 블록을 비동기적으로 실행합니다.
  • DispatchQueue.main.async는 메인 스레드에서 호출합니다.
  • DispatchSemaphore, DispatchGroup, sync 및 qos는 작업 우선 순위를 제어합니다.

함정이 있는 질문.

메인 스레드에서 메인 큐에 sync를 호출하면 어떻게 되나요?

교착 상태가 발생합니다: 메인 스레드는 자신에서 작업 완료를 기다리고 있어 앱이 "멈추게" 됩니다.

DispatchQueue.main.sync { // DEADLOCK }

DispatchQueue.serial이 작업을 병렬로 수행할 수 있나요?

아니요, serial 큐는 항상 작업을 하나씩 수행하지만, 여러 개의 serial 큐를 만들면 서로 병렬로 실행됩니다.

메인 스레드가 아닌 곳에서 UI를 업데이트하는 것이 허용되나요?

아니요, UIKit(또는 SwiftUI View 렌더링)으로의 모든 조작은 DispatchQueue.main에서만 수행할 수 있습니다. 이를 위반하면 불안정한 동작과 충돌이 발생합니다.

일반적인 실수와 안티 패턴

  • 메인 스레드에서 동기 호출(교착 상태)
  • 백그라운드에서 UI 업데이트 시도
  • 공통 변수를 쓰는 동안 관리되지 않는 자원 경합
  • 필요 없이 global queue를 사용하는 것, 전용 큐가 없는 것

실생활 예시

부정적 케이스

백그라운드 스레드에서 데이터를 로드한 후 즉시 UI를 업데이트 — 애플리케이션이 때때로 크래시하거나 인터페이스가 멈추게 됩니다. 또한 스레드 간에 공유 가능한 가변 상태를 동기화 없이 사용합니다.

장점:

  • 코드는 시각적으로 간결합니다.

단점:

  • 불안정한 버그와 발생하기 힘든 크래시
  • 성능 저하

긍정적 케이스

모든 UI 업데이트를 DispatchQueue.main에서만 조직하고, 대용량 데이터 작업을 위한 전용 큐를 사용하며, 비동기 작업 완료를 제어하기 위해 DispatchGroup을 사용합니다.

장점:

  • 경합이 없습니다.
  • 스레드 간의 작업 효율적 분리
  • 유지보수가 쉽습니다.

단점:

  • 스레드 간 "전환"이 많아지고 공유 자원을 다룰 때 규율이 필요합니다.