[Combine] 비동기 이벤트에 컴바인을!

비동기 이벤트는 언제 쓰이나?

J_sung_0o0
4 min readSep 30, 2020
  • Completion Handler: 오랫동안 동작하는 업무가 종료될 때 한번 실행되는 클로져를 제공
  • 클로져 프로퍼티: 비동기 이벤트가 발생할 때마다 실행하기 위함

컴플리션 핸들러 클로져를 Future로 대체하기

아래와 같은 컴플리션 핸들러가 있다고 가정.

func performAsyncAction(completionHandler: @escaping () -> Void) {
DispatchQueue.main.asyncAfter(deadline:.now() + 2) {
completionHandler()
}
}

위 패턴은 컴바인의 Future 로 대체가능.

Future : 업무를 수행하고 난 뒤에 비동기로 성공 또는 실패를 전달하는 퍼블리셔
만약 성공이라면, FuturePromise 가 실행됨

Promise : Future에 의해 생성된 element를 전달 받는 클로져
업무가 완료되면 FuturePromiss를 호출하고 Promiss 에 성공 또는 실패를 가리키는 Result를 담도록 함.

호출자는 이 ResultFuture 로부터 비동기로 전달받음.

func performAsyncActionAsFuture() -> Future <Void, Never> {
return Future() { promise in
DispatchQueue.main.asyncAfter(deadline:.now() + 2) {
promise(Result.success(()))
}
}
}
// 함수의 리턴값이 Future, 즉 퍼블리셔이기 때문에
// `sink(receiveValue:)` 와 같은 Subscriber를 사용하여 접근.
cancellable = performAsyncActionAsFuture()
.sink() { _ in print(“Future succeeded.”) }

Future의 파라미터를 나타낼 때 아웃풋 타입 사용하기

오랫동안 돌아가는 작업이 어떤 값을 생성하는 경우, 즉, 컴플리션 핸들러에 파라미터가 있는 경우 Future 가 퍼블리싱하는 아웃풋 타입으로 파라미터를 선언하여 컴바인으로 대체

// Future가 Int형 element 를 생성한다고 선언
func performAsyncActionAsFutureWithParameter() -> Future <Int, Never> {
return Future() { promise in
DispatchQueue.main.asyncAfter(deadline:.now() + 2) {
let rn = Int.random(in: 1…10)
// Result 타입이 Promise에 Int 값을 전달하도록 사용가능
promise(Result.success(rn))
}
}
}

Promise 를 실행할 때 Future는 그 값을 퍼블리싱하고 호출자는 sink(receiveValue:) 와 같은 subscriber로 전달 받음

cancellable = performAsyncActionAsFutureWithParameter()
.sink() { rn in
print(rn)
}

반복적으로 호출되는 클로저를 Subject로 대체하기

아래와 같은 클로져 프로퍼티가 있다고 가정

vc.onDoSometing = { print(“뭔가 했음”) }

위 패턴은 Subject 로 대체할 수 있음.

Subject

  • send() 메소드를 사용해서 아무 때나 새 element를 퍼블리싱
  • 패턴을 적용할 때는 PassthroughSubject 또는 CurrentValueSubjectprivate 하게 사용하고 AnyPublihserpublic 하게
private lazy var myDoSomethingSubject = PassthroughSubject<Void, Never>()// private 한 PassthroughSubject를 eraseToAnyPubliser 를 통해 외부로 노출
lazy var doSomethingSubject = myDoSomethingSubject.eraseToAnyPublisher()

클로져 프로퍼티 대신에 아래와 같이 sink(receiveValue:) 와 같은 subscriber 를 사용

cancellable = vc.doSomethingSubject
.sink() { print(“Did something with Combine.”) }

에러가 발생하거나 더이상 이벤트가 없을 때 send(completion:) 을 사용

--

--

J_sung_0o0
J_sung_0o0

Written by J_sung_0o0

Apple WWDC 19 & 20 Winner (The 1st two-time winner of all time from South Korea)

No responses yet