반응형
주의해야 하는 사항
1. UI 관련한 작업은 반드시 메인 스레드로 보내줘야한다. (DispatchQueue.main.async)
DispatchQueue.global().async {
// 네트워크 통신 (데이터 다운로드)
DispatchQueue.main.async {
// UI와 관련된 작업
}
}
2. 비동기 처리를 하는 함수에서는 return 문으로 반환하면 비동기적 실행으로 인해 nil을 return하므로, 탈출 클로저를 사용하여 결과값을 반환해야한다. (Apple에서는 이를 completion Handler라고 명칭함)
func getImages(url: String, completionHandler: @escaping (UIImage?) -> Void) {
let url = URL(string: url)!
URLSession.shared.dataTask(with: url) { (data, response, error) in
....// 작업 작업
completionHandler(photoImage) //콜백을 통해 결과 전달
}.resume()
}
getImages(with: "url") { (image) in
print(image)
DispatchQueue.main.async { //photoImage를 전달받으면,
// UI관련작업
}
}
3. URLSession(이를 활용하는 라이브러리인 Alamofire, Moya 모두 포함)은 원래 비동기처리가 되어있음을 인지하고 프로그래밍해야한다. (안에서 UI를 만지는 코드가 있으면 따로 메인 스레드로 보낸다든지 등)
URLSession.dataTask(with: url) { [weak self] result in
switch result {
case .success(let data):
DispatchQueue.main.async { // UI 작업은 메인 스레드로 보내기
let secondVC = self?.storyboard?.instantiateViewController(withIdentifier: "secondVC") as! SecondViewController
secondVC.str = (data.data ?? []).description
self?.present(secondVC, animated: true)
}
case .failure(let error):
print(error)
}
}
4. 객체 내에서 GCD 사용시 - 강한 참조 사이클 (메모리 누수) 발생 가능성
class ViewController: UIViewController {
var name: String = "조이"
func doSomething() {
DispatchQueue.global().async {
sleep(3)
print("글로벌큐에서 출력하기: \(self.name)")
}
}
deinit {
print("\(name) 메모리 해제")
}
}
이렇게 DispatchQueue가 클래스 내에 있을 때
변수에 할당하는 경우 강한 참조 사이클이 발생하며, 할당하지 않더라도 이미 해제되었어야 할 뷰컨을 더 오래 붙잡는 경우가 발생하기 때문에 이를 방지하기 위해서 가급적이면 weak self를 사용하는 것이 좋다.
func doSomething() {
// 강한 참조 사이클이 일어나지 않지만, 굳이 뷰컨트롤러를 길게 잡아둘 필요가 없다면
// weak self로 선언
DispatchQueue.global().async { [weak self] in
sleep(3)
guard let weakSelf = self else { return }
print("글로벌큐에서 출력하기: \(weakSelf.name)") // 출력X
}
}
reference
반응형
'🍎 iOS > GCD' 카테고리의 다른 글
[iOS/GCD] 4. async/await (Swift 5.5 ~) (feat. vs Combine, RxSwift) (0) | 2023.07.24 |
---|---|
[iOS/GCD] 2. GCD의 개념 및 종류 (0) | 2023.03.10 |
[iOS/GCD] 1. 코어/스레드/프로세스, 직렬/병렬/동시, 동기/비동기 (0) | 2023.03.10 |