본 게시물은 앨런의 인프런 강의를 듣고 작성한 글 입니다.
1. 반드시 메인큐에서 처리해야하는 작업
예전에 디스패치큐에 대해 얕게 공부할 때 스택오버플로우에서 UI와 관련된 작업은 메인큐에서 처리해야한다는 글을 본 적이 있다. 그때는 그냥 그렇구나 하고 넘어갔는데 그냥 내 머리에 "UI작업 -> 메인에서 처리해야함" 이정도로만 인식하고 있었다.
이번에 비동기에 대해 좀 더 자세히 공부하면서 UI관련 작업은 메인에서 처리해야함을 다시 듣게 되었고, 그 이유도 함께 알게 되었다.
생각해보면 간단하다. 다른 스레드로 분산해서 처리한다면 작업의 순서가 일정하지 않고, 다른 스레드에서 나눠서 처리하면서 간섭이 일어나게 되면서 화면이 깜빡거리는 등의 제대로 된 화면을 사용자에게 제공하기 어려울 수 있다.
메인큐에서 처리해야한다고 했지만 사실 메인으로 다시 돌아가야하는 작업이 번거로울 뿐 한개의 스레드에서 담당하면 된다고 한다.
DispatchQueue.global().async {
// code
DispatchQueue.main.async {
self.imageView.image = image // UI관련 작업
}
}
위와 같은 코드가 있을 때, global큐에서 처리하던 작업을 main에서 처리하고 있다.
UI관련 작업이기 때문에 위와 같은 방식으로 main큐에서 처리하고 있음을 확인할 수 있다.
2. sync메서드에 대한 주의사항
(sync 메서드와 관련해 절대 해서는 안되는 코드 2가지)
1) 메인큐에서 다른큐로 보낼때 sync메서드를 부르면 절대 안된다.
sync가 아닌 async를 사용해야한다. 즉, 메인큐에서는 항상 비동기적으로 보내야한다.
왜냐하면 sync를 사용하면 비동기적으로 처리하지 않기 때문에 하나의 작업이 끝날 때 까지 기다리게 된다.
그라면 화면을 담당하는 작업은 버벅이는 현상과 같이 UI가 멈춰 유저에게 늦게 반응하게 때문에 올바른 화면을 유지하기 위해서는 사용하면 안된다.
2) 현재의 큐에서 현재의 큐로 동기적으로 보내서는 안된다.
DispatchQueue.global().async {
DispatchQueue.global().sync {
}
}
// 이렇게 사용하지 않는다.
즉, async로 보낸것을 다시 sync로 보내는 행동을 해서는 안된다는 것이다.
그 이유는 현재의 큐를 블락하는 동시에 다시 현재의 큐에 접근하기 때문에 교착상황이 발생한다.
교착상황이란 간단히 말해 어떠한 이유에서간에 작업 진행이 멈춰, 진행되지 못하는 상황을 의미한다.
만약 어떤 작업을 비동기적으로 스레드에 보낸다면 보낸 즉시 다시 큐로 돌아온다. 이때 다시 동일한 스레드로 접근한다면 이미 block으로 막아버렸는데 다시 접근했기 때문에 교착상태가 된다.
무조건 교착상태가 일어나는건 아니다. 보낸 동일한 스레드에 접근한게 아니라 다른 스레드에 다시 배치되었다면 교착상태가 발생하지 않지만 교착상태가 발생할 위험이 있기 때문에 이 방법을 지양한다. 또한 직렬큐일때도 교착상황이 발생하지 않는다.
3. weak, strong캡쳐 주의
DispatchQueue.global(qos: .utility).async {[weak self] in
guard let self = self else { return }
DispatchQueue.main.async {
self.textLabel.text = "New Posts updated!"
}
}
위 코드에서 첫번째 디스패치큐에서는 [weak self]를 적어준다. 이때 객체에 대한 캡쳐현상이 발생하는데 이때 그 내부에 있는 디스패치큐(메인)에도 [weak self]를 적어준것과 동일하게 동작한다.
4. (비동기 작업에서) 컴플리션핸들러의 존재이유
비동기로 작업을 시킨 후 작업에 해댱하는 겂을 바로 사용하면 안된다.
작업이 아직 종료하지 않았는데 해당 값에 접근하면 잘못된 값을 사용할 확률이 높다.
그래서 해당 비동기 작업이 끝났다는 것을 정확히 알려주는 시점이 컴플리션핸들러이다.
비동기 함수와 관련된 작업들은 모두 컴플리션핸들러를 가지고 있다.
간단한 작업일 때는 괜찮아도 오래 걸리는 작업은 끝나는 시점을 알아야한다. 이 시점을 컴플리션 핸들러라 한다.
5. 동기적 함수를 비동기 함수처럼 만드는 방법
여러번 재활용 하기 위해 이 방법을 사용한다. 동기적 방법이 오래걸리다 보니 내부적으로 비동기적 동작을 하게 하고 싶어져 이 방법을 사용한다.
URLSession과 같은 비동기함수는 이미 GCD와 Operation이 내장되어 있기 때문에 필요하지 않다.
'iOS' 카테고리의 다른 글
[iOS] 동시성과 관련된 문제 (Concurrency Problems) (0) | 2022.12.16 |
---|---|
[iOS] 디스패치 그룹(Dispatch Group) (0) | 2022.12.13 |
[iOS] 디스패치큐(GCD)의 종류와 특성 (메인큐, 글로벌큐, 프라이빗큐) (0) | 2022.12.07 |
[iOS] GCD와 Operation, 동기와 비동기, 직렬과 동시 (1) | 2022.12.05 |
[iOS/Swift] Github OAuth - 깃허브 로그인 구현하기 (2) | 2022.10.08 |