iOS 비동기 처리 PromiseKit, Bolts, RxSwift
iOS 비동기 처리 방식
DispatchQueue를 이용한 처리
    @IBAction func loadImageAsync(_ sender: Any) {
        // TODO: async
        // Queue 에는 sync async ConcurrencyQueue와 serialQueue 총 네개존재
        DispatchQueue.global().async {
            // async하게 작용
            let image = self.getImage(from: self.IMAGE_URL)
            // UI업데이트는 main에서
            DispatchQueue.main.async {
                self.imageView.image = image
            }
        }
    }
        private func getImage(from imageUrl: String) -> UIImage? {
        guard let url = URL(string: imageUrl) else { return nil }
        guard let data = try? Data(contentsOf: url) else { return nil }
        let image = UIImage(data: data)
        return image
    }
iOS에서 기본으로 제공하는 DispatchQueue를 이용해서 이미지를 다운로드 받는 코드이다. 우선 DispatchQueue에서 제공하는 큐는 네가지의 종류가 있다.
- ConcurrencyQueue sync / async
 - SerialQueue sync / async
 
위의 코드에선 기본으로 제공하는 DispatchQueue를 이용하여 global Queue와 main Queue를 나누어 수행 해 주었다. 이미지를 받아오는 작업을 크게 global async 로 그 안에 UI를 변경하는 작업 즉 imageView를 변경시킨 작업은 main 스레드 에서 작업하도록 main Queue를 사용하였다.
#####
PromiseKit을 이용한 처리
iOS의 비동기 제어를 위한 외부라이브러리 중 많은 사람들이 사용하는 PromiseKit 이다. 간단하게 사용법을 정리하겠다.
Escaping Closure 사용
우선 DisaptchQueue를 이스케이핑 클로저 함수 내부에 넣어 이미지를 받아오는 작업을 하고 난 다음 성공한 이미지 객체를 반환하는 코드를 작성한다.
func asyncLoadImage(from imageUrl: String, completed: @escaping (UIImage?) -> Void) {
    DispatchQueue.global().async {
    		guard let url = URL(string: imageUrl) else { return nil }
    		guard let data = try? Data(contentsOf: url) else { return nil }
    		let image = UIImage(data: data)
        completed(image)
    }
}
 @IBAction func loadImageAsync(_ sender: Any) {
        imageView.image = nil
        
        // 함수가 Promise<Image> 객체를 반환하기 때문에 .done .catch로 제어가 가능하다.
        promiseLoadImage(from: LARGER_IMAGE_URL)
            .done { image in
                self.imageView.image = image
            }.catch { error in
                print(error.localizedDescription)
            }
    }
    // MARK: - PromiseKit
    func promiseLoadImage(from imageUrl: String) -> Promise<UIImage?> {
        return Promise<UIImage?>() { seal in
            // 비동기적으로 이미지 다운로드
            asyncLoadImage(from: imageUrl) { image in
                // seal 에게 완료가 되었는지 넘겨준다.
                seal.fulfill(image)
            }
        }
    }
위에서 promiseLoadImage(from:) 함수 에서 비동기적으로 이미지 파일을 다운 받고 성공을 하면 seal 객체에 fulfill() 매서드를 통해 이미지를 넘겨 준다. 마찬가지로 이 함수는 PromiseKit의 Promise<T> 를 반환하는 함수기 때문에 .done 과 .catch 로 핸들링이 가능하다.
BoltsSwift를 이용한 제어
BoltsSwift도 비동기 제어를 위한 외부라이브러리이다. 기본적인 구조는 PromiseKit과 비슷하다 제공하는 함수만 다를 뿐이다.
 @IBAction func onLoadImage(_ sender: Any) {
        imageView.image = nil
        boltsLoadImage(from: LARGER_IMAGE_URL)
            .continueWith(continuation: { task in
                DispatchQueue.main.async {
                    let image = task.result
                    self.imageView.image = image
                }
            })
    }
    // MARK: - Bolts
    func boltsLoadImage(from imageUrl: String) -> Task<UIImage> {
        let taskCompletionSource = TaskCompletionSource<UIImage>()
        asyncLoadImage(from: imageUrl, completed: { image in
            guard let image = image else {
                taskCompletionSource.cancel()
                return
            }
            taskCompletionSource.set(result: image)
        })
        return taskCompletionSource.task
    }
Bolt에서는 Task
그렇게 성공한 값은 .continueWith() 메서드를 통해 성공한 값은 클로저로 작성한 task 매개변수의 result를 통해 접근하여 가져올 수 있다.
RxSwif의 제어 방식
사실 기존의 Async(비동기) 하게 무언가를 작업을 수행하는 궁극 적인 목적은 위의 외부라이브러리나 다 동일하다.
RxSwift 에서 궁극적으로 추구하는 것은 조금 더 쉽게, 조금 더 간결하게 이다.
