안녕하세요 린다입니다.
저번 GCD 정리에 이어서.. GCD 사용시 주의해야할 사항을 정리해보았어요.
본 정리는 앨런님의 강의를 수강하면서 이해하고 정리한 내용입니다!!
(https://sy-catbutler.tistory.com/31)
밑에서부터 편한 말투로 써볼게요!
DispatchQueue 사용시 주의해야할 사항
1) 반드시 메인큐에서 처리해야하는 작업
→ UI 관련된 일들은 “메인큐”에서 처리해야 한다!!
즉, 화면을 담당하는 업무는 하나의 쓰레드에서만 작업되어야만 한다.
예를 들어.. 메인쓰레드(1번 쓰레드)에서 Queue로 Task을 보냄
→ Queue에서 2번쓰레드로 Task 보냄
→ 근데 Task에 UI 관련 동작이 있음
→ 이 부분은 다시 메인쓰레드로 보내서, 메인 쓰레드에서 동작해야함
DispatchQueue.global().async(
// 이미지 다운로드 등 관련 코드
// ...
DispatchQueue.main.async {
// 다운로드한 이미지 표시 코드
self.imageView.imgae = image
}
}
DispatchQueue.global().async
→ 여러쓰레드를 사용해서 처리하기 위해 대기열큐에 글로벌하게 비동기적
(다른 쓰레드로 보낸 일의 완료 유무를 기다리지 않고)으로 보낸다.
→ 다운로드한 후, 화면과 관련하여 이미지를 표시해주고 싶은 작업이 있다면,
반드시 main에서 일어날 수 있도록 main.async 로 보내주어야함!
즉.. 한마디로 정리하면,
사진 다운로드는 오래 걸리는 작업이니, 비동기로 분산해서 작업을 처리하고 싶음 (글로벌이나 다른 쓰레드로 보내서)
근데 다운로드한 사진을 사용하는 것은 UI에서 일어나는 일이니, 이런 작업들은 다시 메인큐로 보내는 코드가 필요함!!
2) Sync 메서드에 대한 주의사항
*sync 메서드와 관련해서 절대 해서는 안 되는 코드 2가지
[1] 메인큐에서는 다른큐로 보낼때 sync 메서드를 부르면 절대 안 된다.
- 메인 큐에서는 항상 비동기적으로 보내야 함
- 즉, 메인에서 다른 큐로 일을 보내는데 sync를 사용하면 보내는 메인에서도 다른 큐에서 작업이 다 완료되고 돌아와야 다른 일을 할 수 있다는 것을 의미하기 때문에.. 이렇게 되어버리면, UI를 담당하는 메인큐는 기다리는 그 시간만큼 버벅이게 됨
DispatchQueue.global().sync { } 금지
[2] 현재의 큐에서는 현재의 큐로 동기적으로 보내서는 안 된다.
-> 현재 큐를 블락하는 동시에 다시 현재의 큐에 접근하기 때문에 교착상황이 발생할 확률이 높아진다.
DispatchQueue.global().async {
DispatchQueue.global().sync {
//...
}
}
코드 설명)
- 메인쓰레드에서 비동기로 → 큐로 작업 보냄
- 큐 → 2번 쓰레드로 작업을 보냄 (global 이니까)
근데 이 2번쓰레드에서 다시 큐로 sync, 동기 작업으로 보냄
- 그러면 2번 쓰레드는 “동기”이기 때문에 일단, 큐로 작업을 보내고 block됨
- 큐는 또 global으로 받았기 때문에 다시 어떤 쓰레드한테 일을 보낼건데… 보내지는 쓰레드가 다시 2번쓰레드가 되는 순간, 교착 상태에 빠져버림
→ 왜? 현재 2번쓰레드는 일이 완료될때까지 블락된 상태인데, 그 일이 돌고 돌아서 다시 자기 자신에게 와버린 것
→ 그래서,,, 만약 2번쓰레드가 아닌 다른 스레드로 가게 된다면, 교착상태에 빠지지는 않음
그러나, 해당 코드가 교착상태에 빠질 위험성을 항상 내포하고 있다는 것을 의미하기 때문에 현재 큐에서 현재큐로 동기적인 작업을 보내면 안된다는 것!!
3) weak, strong 캡처 주의
쓰레드에서 작업을 보내는 일 == 클로저를 보내는 것, 객체에 대한 캡쳐 현상이 발생할 수 있음!
그렇기 때문에 적절한 weak, unowned를 사용해야함!
4) (비동기 작업에서) 컴플리션핸들러의 존재이유
우리는 지금 비동기를 사용중일때!!
지금 task1번, 오래 걸릴 수 있는 작업임을 인지 하고 있다는 것임 그래서, 비동기로 일을 보냄
근데 이때 만약에,, 1번 작업이 언제 끝나는지 알 수 있는 방법은? → 에서 나온 것이 컴플리션핸들러
예) 다운로드 작업이라면, 작업이 언제 끝나는지?와 같은 경우
즉, 비동기로 작업을 시키고 나서 작업이 끝났는지 아닌지를 모르는데
그 작업에 접근해서 값을 사용하려고 하면 잘못된 값을 사용할 확률이 높음.
그래서, 해당 비동기 작업이 언제 끝났는지에 대한 시점을 알려주는 것이 컴플리션핸들러!!
→ 비동기 함수와 관련된 작업들은 모두 컴플리션핸들러를 가지고 있음!
5) 동기적 함수를 비동기함수로 바꾸기
→ 원래 동기인 함수를 비동기로 바꿔서 사용하기 위해서는…
- 동기함수를 비동기로 실행할 큐가 필요함
- 비동기로 실행한다면 그 결과값을 받아서 실행할 컴플리션핸들러에도 큐가 필요함
이게 무슨 말이나면..
만약 동기적으로 실행되는 함수가 있는데 이거를 비동기적으로 실행하고 싶다면,
먼저 비동기적으로 실행하기 위한 큐로 함수를 보내고
비동기로 끝나는 작업을 컴플리션핸들러로 사용해서 결과물에 따른 처리를 할거니까
이때 사용할 큐가 하나 더 필요하다는 말..
-> 4,5 번에 관련한 사항은 직접 강의를 보시는게.. 좋을것 같슴니다.
예시를 그대로 가져오면 안 될거 같은데 생각나는 좋은 예시가 없어서요 (?)
일단은 이렇게 1차 GCD 마무리를 짓고...
GCD Group를 듣고 정리할게 또 생긴다면, 정리하러 오겠습니다~
'Swift > Swift 기초문법' 카테고리의 다른 글
Swift 기초 문법, 함수와 클로저를 톺아보자 ... 2번째 (1) | 2024.02.06 |
---|---|
Swift 기초 문법, 함수와 클로저를 톺아보자 (1) | 2024.02.06 |
DispatchQueue(GCD)를 알아보자, 이제 동기/비동기, 동시/직렬을 곁들인.. (2) | 2023.11.03 |
[Swift 기초문법] Error Handling을 알아보자 (0) | 2023.07.17 |
[Swift 기초문법] @State, @Binding 을 알아보자 (0) | 2023.07.10 |