왜 동시성 프로그래밍이 필요할까?
큐만 만들어서 넣으면 iOS가 알아서 교통정리를 해준다
DispatchQueue.global().async {
}
특징
- 직접적으로 쓰레드를 관리하지 않고, 큐라는 개념을 이용해 작업을 분산 처리
- GCD / Operation을 사용해 시스템에서 알아서 쓰레드 숫자를 관리함
- 쓰레드 보다 더 높은 레벨/차원 에서 일을 한다고 보면됨
- 쉽게 다른 쓰레드에서 오래걸리는 작업들이 비동기적으로 동작하도록 만들어줌
GCD : Grand Central Dispatch = 디스패치큐
- 간단한 일
- 함수 사용하는 작업 (메서드 위주)
Operation : 오퍼레이션 큐
- 복잡한 일
- 데이터와 기능을 캡슐화한 객체
- GCD 기반으로 만들어짐 + 여러가지 다른 기능
GCD or Operation?
- 프로젝트의 효율성, 사례 적합성 등을 활용해 선택해서 사용할 것!
Synchronous vs Asynchronous
- 비동기는 task가 끝날때까지 메인큐에서 기다리지 않음
- 작업을 다른 쓰레드에서 하도록 시킨 후, 그 작업이 끝나길 안 기다리고 다음 일을 진행
- 동기는 기다림.
- 작업을 다른 쓰레드에서 하도록 시킨 후, 그 작업이 끝나길 기다렸다가 다음 일을 진행
비동기가 필요한 이유
- 대부분은 서버와의 통신(네트워크 작업) 때문이다
- 네트워크와 관련된 작업들은 내부적으로 비동기적으로 구현되어있다
Serial vs Concurrency 직렬과 동시
- 큐의 특성에 관한 것이다
- 몇개의 쓰레드로 분산할지는 시스템이 알아서 결정
직렬 큐
- 다른 한개의 쓰레드에서 처리하는 큐
- 순서가 중요한 작업을 처리할 때 사용
동시 큐
- 다른 여러개의 쓰레드에서 처리하는 큐
- 독립적이지만 유사한 여러개의 작업을 처리할 때 사용
비동기 = 동시?
- 작업을 보내는 시작점에서 기다릴지 말지 → 비동기
- 대기열로 보내진 작업이 여러개의 쓰레드로 갈건지(동기) 한개로 갈건지(직렬) → 동시
2. 디스패치큐(GCD)의 종류와 특성
대기열마다 특성이 좀 다르다.
작업의 특성, 원하는 일처리에 따라 대기열(큐)의 특성에 맞게 작업을 보내면 된다
메인 큐
글로벌 큐와 QOS의 이해
-
알아서 여러개로 나눠서 실행해주는 큐다
-
중요한 순서대로 큐
-
.userInteractive
- 거의 즉시, UI
- 유저와 직접적으로 상호 작용
-
.userInitiated
- 유저가 즉시 필요하긴 하지만 비동기 : 앱 내에서 pdf 파일 여는 것과 같은
-
default
-
.utility
- 몇초에서 몇분
- progress indicator와 함께 길게 실행되는 작업, 계산, IO, 네트워킹, 지속적인 데이터 feeds
-
.background
- 속도보다는 에너지 효율성 증시, 몇분 이상
- 유저가 직접적으로 인지하지 않고 시간이 안중요한 작업
- 데이터 미리 가져오기
- DB 유지
-
.unspecified
프라이빗(커스텀) 큐
- 커스텀으로 만든다
- 디폴트 설정(Serial)
- Concurrent 설정 가능
- Qos 설정도 가능하다
3. 디스패치 큐 사용시 주의해야할 사항
반드시 메인큐에서 처리해야하는 작업

Sync 메서드에 대한 주의사항 (sync 관련 절대 X)
-
메인큐에서는 다른 큐로 보낼 때 sync 메서드를 부르면 절대 안된다
- 메인큐에서는 항상 비동기적으로 보내야한다. → async
- sync → 다른 쓰레드로 보낸 작업 기다림 → 화면 버벅거림 발생할 수 밖에 없다
-
현재의 큐에서 현재의 큐로 동기적으로 보내서는 안된다. → 데드락의 발생 가능성이 존재한다
DispatchQueue.global().async {
DispatchQueue.global().sync {
}
}
weak, strong capture 주의
- 객체에 대한 캡쳐 현상
- 뷰컨트롤러 이미 소멸 됐는데 아직 돌아가고 있을수도 . . .
컴플리션 핸들러의 존재 이유
- 비동기로 작업을 시키고 나서 작업에 해당하는 값을 바로 사용 x
- 아직 종료되지 않았는데 해당 값 접근시 잘못된 값 사용할 확률 높음 → completionHandler
동기적 함수를 비동기 함수 처럼 만드는 방법
- 여러번 재활용하기 위해서
- 동기 함수 너무 오래 걸려서 → 비동기 처럼!!
캡처리스트의 [weak self]에 대한 이해
클래스의 인스턴스(객체), 클로저 ===> 힙 메모리에 할당
-
클래스 인스턴스
변수를 weak, unowned로 선언 ===> 인스턴스를 참조하되, RC가 올라가지 않게 하므로 강한 참조 사이클 일어나지 않음
-
클로저
클로저의 캡처리스트내에서 + weak, unowned로 선언 ===> 인스턴스를 참조하되, RC가 올라가지 않게 하므로 강한 참조 사이클 일어나지 않음