🍎 iOS/GCD

[iOS/GCD] 3. GCD의 주의사항

dev_zoe 2023. 7. 23. 20:54
반응형

주의해야 하는 사항

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

앨런 Swift 문법 마스터스쿨

야곰닷넷 - 동시성 프로그래밍

반응형