티스토리 뷰
앱을 개발하다 보면 이런 상황을 자주 만나게 된다.
- 네트워크 요청을 보냈는데 응답이 느려서 UI가 멈춘다.
- 이미지 로딩이 오래 걸려서 스크롤이 끊긴다.
- 데이터 연산이 많아서 앱이 버벅인다.
이런 문제를 해결하려면 비동기 처리를 해야 하는데, 이때 가장 많이 사용하는 게 바로 GCD(Grand Central Dispatch) 다. iOS에서 멀티스레딩을 쉽게 다룰 수 있도록 도와주는 API다.
이번 글에서는 GCD가 뭔지, 어떻게 동작하는지, 그리고 실무에서 어떻게 활용할 수 있는지 알아보자!
GCD(Grand Central Dispatch)란?
GCD는 iOS에서 멀티스레딩을 쉽게 다룰 수 있도록 도와주는 프레임워크다. 쉽게 말해, 실행할 작업을 큐(queue)에 넣으면 적절한 시점에 실행해 준다.
"멀티스레딩이 왜 필요할까?"
앱에서 모든 작업을 메인 스레드에서 실행하면 화면이 멈추거나 버벅거릴 수 있다.
GCD를 사용하면 무거운 작업을 백그라운드에서 실행하고, UI 업데이트는 메인 스레드에서 처리할 수 있다.
DispatchQueue란?
GCD에서 작업을 실행하는 공간이 큐(DispatchQueue) 다.
여러 개의 작업을 큐에 넣으면 순서대로 실행하거나 동시에 실행할 수 있다.
큐의 종류
큐 종류 실행 방식 특징
| 큐 종류 | 실행 방식 | 특징 |
| 직렬 큐(Serial Queue) | 순차 실행 | 한 번에 하나의 작업만 실행 |
| 동시 큐(Concurrent Queue) | 동시 실행 | 여러 개의 작업을 동시에 실행 |
직렬 큐는?
→ "한 작업이 끝나야 다음 작업을 실행하는 방식"동시 큐는?
→ "여러 작업을 동시에 실행하지만, 언제 끝날지는 알 수 없는 방식"
직렬 큐 예제
let serialQueue = DispatchQueue(label: "com.example.serialQueue")
serialQueue.async {
print("Task 1 시작")
sleep(2) // 2초 대기
print("Task 1 완료")
}
serialQueue.async {
print("Task 2 시작")
sleep(1) // 1초 대기
print("Task 2 완료")
}
출력 결과:
Task 1 시작
(2초 대기)
Task 1 완료
Task 2 시작
(1초 대기)
Task 2 완료
✅ 하나씩 순차적으로 실행됨
동시 큐 예제
let concurrentQueue = DispatchQueue(label: "com.example.concurrentQueue", attributes: .concurrent)
concurrentQueue.async {
print("Task 1 시작")
sleep(2)
print("Task 1 완료")
}
concurrentQueue.async {
print("Task 2 시작")
sleep(1)
print("Task 2 완료")
}
출력 결과 (실행할 때마다 달라질 수 있음):
Task 1 시작
Task 2 시작
Task 2 완료
Task 1 완료
✅ 여러 작업이 동시에 실행됨
DispatchQueue를 활용하는 방법
1. 메인 스레드에서 UI 업데이트
네트워크 요청을 보낸 후 UI를 업데이트할 때는 반드시 메인 스레드에서 실행해야 한다.
DispatchQueue.global().async {
let image = downloadImage() // 백그라운드에서 이미지 다운로드
DispatchQueue.main.async {
imageView.image = image // UI 업데이트 (메인 스레드에서 실행)
}
}
✅ 백그라운드에서 이미지를 다운로드한 후, 메인 스레드에서 UI를 업데이트!
2. 작업을 일정 시간 후에 실행하기 (딜레이 처리)
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
print("3초 후 실행됨")
}
✅ 3초 후에 코드가 실행됨
3. 특정 작업이 끝난 후 실행하기 (그룹 작업)
여러 개의 작업이 끝난 후 특정 코드를 실행해야 할 때는 DispatchGroup을 사용할 수 있다.
let group = DispatchGroup()
let queue = DispatchQueue.global()
group.enter()
queue.async {
sleep(2)
print("작업 1 완료")
group.leave()
}
group.enter()
queue.async {
sleep(1)
print("작업 2 완료")
group.leave()
}
group.notify(queue: .main) {
print("모든 작업 완료 후 실행됨")
}
✅ 모든 비동기 작업이 끝난 후 실행됨
GCD를 사용할 때 주의할 점
- UI 업데이트는 항상 메인 스레드에서!
→ 백그라운드 작업을 실행한 후 DispatchQueue.main.async로 UI를 업데이트해야 한다. - Deadlock(교착 상태)을 조심하자
→ sync를 잘못 사용하면 스레드가 멈출 수 있다.
→ sync는 현재 스레드에서 실행을 기다리므로, 같은 큐에서 호출하면 문제가 발생한다.
let queue = DispatchQueue(label: "com.example.queue")
queue.sync {
print("작업 1 시작")
queue.sync { // 같은 큐에서 sync 호출 → Deadlock 발생!
print("작업 2 시작")
}
print("작업 1 완료")
}
⚠️ 실행하면 앱이 멈춰버림!
정리
GCD는 iOS에서 비동기 작업을 쉽게 처리할 수 있도록 도와주는 필수적인 도구다.
이번 글에서 다룬 내용을 정리해 보면:
✅ DispatchQueue를 사용해 작업을 백그라운드에서 실행할 수 있다.
✅ 메인 스레드에서 UI를 업데이트해야 한다.
✅ 직렬 큐는 순차 실행, 동시 큐는 여러 작업을 동시에 실행한다.
✅ async, sync, DispatchGroup 등을 활용해 다양한 비동기 작업을 제어할 수 있다.
GCD를 잘 활용하면 앱이 더 빠르고 부드럽게 동작할 수 있다.
언급한 내용 말고도 다양한 활용법과 기능이 있다
멀티스레딩을 깊게 이해하려면 앞으로도 꾸준한 공부가 필요해 보인다
'iOS' 카테고리의 다른 글
| OperationQueue - iOS에서 비동기 작업을 효율적으로 관리하는 방법! (0) | 2025.02.27 |
|---|---|
| Async/Await 완벽 정리 – 왜 써야 할까? 어떻게 써야 할까? (0) | 2025.02.26 |
| Run Loop – iOS 앱은 어떻게 끊기지 않고 동작할까? (0) | 2025.02.24 |
| 캡처 리스트(Capture List) – 클로저가 변수를 기억하는 방법 (0) | 2025.02.21 |
| RxSwift - Concat 과 Merge (0) | 2024.02.26 |