본문 바로가기
iOS/iOS

Promises

by 헤콩 2021. 4. 29.
반응형

보통 Swift에서 비동기처리를 구현할 때는 delegate 패턴을 사용하거나 RxSwift를 활용하는 등의 방법을 사용합니다. 저도 지금까지 개인프로젝트를 진행할 때 RxSwift에 익숙해질 겸 RxSwift+MVVM 구조를 적용하려고 노력했는데요, 이번에 동아리 프로젝트에서 RxSwift가 아닌 Promises를 사용해보자는 이야기가 나와서 Promises에 대해 한 번 알아보려 합니다.

 

RxSwift는 주로 사용되는 기능들 외의 다른 수많은 기능들은 잘 사용되지 않을 때가 있는데요, 그래서 간단한 프로젝트에서는 사용되지 않는 기능들까지 pod파일로 가지고 있어야 해서 사용해야하는 메서드에 비해 파일의 양이 방대해집니다. 그래서 이번에 구현하려는 개인 프로젝트에서는 Promises를 연습해볼겸 Promises를 적용해보려 합니다 :)

 

 

Installation

pod 'PromisesSwift'

 

 

What is promises

Promises는 Swift에서 비동기처리를 Promise 라는 객체로 묶어서 그 상태 값이 결정 (resolved: fulfill or reject) 되면 다음 동작을 할 수 있게끔 구현한 구조입니다. 여기서 결정된 상태라는 것은 비동기처리의 completion을 말합니다.

 

보통 completion handler나 delegate를 사용해서 비동기처리를 구현하면 중첩 레벨이 늘어나면서 가독성이 떨어지는 경우가 있습니다. 하지만 Promises를 사용하면 이런 비동기처리에서의 가독성과 퍼포먼스를 높여줄 수 있습니다.

 

예를 들면, 어떠한 다른 스레드에서 일을 처리하다가 main 스레드에서 UI 업데이트를 할 때 다음과 같은 코드가 꼭 들어가야 하는데, 이게 if문 안에 있다면 벌써 tab이 3번이나 들어가게 되죠.

 

if isSuccess {
    DispatchQueue.main.async {
        self.label.text = "success"
    }
}

 

 

Promise는 아래 3가지 상태 중 하나를 가질 수 있습니다.

Promise는 한번 fulfill이나 reject 상태가 되면 다시 상태를 바꿀 수 없습니다. 그렇기 때문에 수많은 observer들이 해당 promise가 resolved 되기를 기다리게 됩니다. 그러다가 resolved되면, fulfilled 되어 observer들에게 value를 전달하거나 rejected되어 error를 전달합니다. 그리고 여러 Promise들을 체인 걸듯이 연결해서 서로 다른 스레드에서 비동기적으로 반환되는 값들을 엮어서 사용할 수도 있습니다.

 

따라서 Promises는 비동기적인 작업들을 체이닝 형식으로 만들어서 더 쉽게 completion handler를 처리할 수 있도록 합니다. 예를 들면 아래와 같은 작업들도 수행할 수 있겠죠?

  • 서로 의존적인 비동기 작업들을 엮어서 결국 하나의 completion 블록을 실행하도록 구현할 수 있습니다.
  • 많은 독립적인 비동기 작업들을 하나의 completion 블록으로 동시에 수행할 수 있습니다.
  • 많은 비동기 작업들을 경쟁하듯 실행시켜서 완료할 첫 번째 값을 반환시킬 수 있습니다.
  • 비동기 작업을 retry 할 수 있습니다.

 

 

Creating promises

Promise를 생성하는데에는 2가지 방식이 있습니다. 우리가 어떠한 비동기 작업이 끝나고 나서 실행하고 싶은 pending된 promise를 필요로 하는지, 아닌지에 따라 달라지죠.

 

- Create a pending promise

 

Promise 작업 블록에 비동기 처리가 필요하지 않은 경우에는  do 연산자  를 사용해서 더 간결하게 작성할 수도 있습니다.

 

또는, 아래와 같이 작성한다면 아래 promise가 반환하는 Promise<String>을 또 다른 스레드가 체인을 걸 수도 있겠죠?

 

그리고 다른 관련된 비동기 작업을 할 필요 없이 그냥 pending된 promise가 필요할 때는 pending( )을 사용하면 됩니다.

 

 

- Create a resolved promise

가끔 이미 fulfill이나 reject된 promise를 만들어서 사용하는게 편리한 경우가 있는데, 이때는 Promise의 초기값이나 에러를 전달해서 사용합니다.

 

 

Observing fulfillment

promise가 resolved 됐을 때 notify되는 그 값을 우리가 사용하기 위해서는  then 연산자  를 사용해야합니다.

 

여기서 가장 중요한 점은 여러 promise들을 체이닝할 수 있다는 사실입니다.

 

 

Observing rejection

reject된 promise는  catch  연산자  를 사용해서 notify된 값(에러)을 얻을 수 있습니다.

 

그리고 catch 연산자를 활용해서 체이닝을 한다면 아래와 같은 예시를 볼 수 있죠

 

 

 

 

 

사실 Promise 깃허브 introduction 마크다운 파일을 보면 더 많은 Extension 정보들도 있는데, 일단 본 게시물에서는 기본적인 정보들만 요약을 해보고 여기서 마무리 지어보겠습니다 :)

 

 

Reference

반응형

댓글