Do.

Swift - RxSwift의 withUnretained를 Combine에서도 쓰기 본문

iOS

Swift - RxSwift의 withUnretained를 Combine에서도 쓰기

Hey_Hen 2023. 5. 2. 14:48

개요

RxSwift나 Combine 등에서 subscribe에서 escaping closure를 다룰 시 필연적으로 캡처 리스트를 통해 약한 참조를 해야할 때가 있습니다. 아주 지긋지긋 하죠? Xcode 14.3(swift 5.8) 이후 부터는 weak self를 바인딩 한번 한 이후 부터는 self를 붙일 필요가 없긴 합니다만.. 바인딩 코드를 작성하는 것도 매우 귀찮은 일..

 

이를 RxSwift(6.0)에서는 withUnretained라는 설탕 문법이 있습니다.

observerble
 .withUnretained(self)
 .subscribe { (owner, output) in
   owner.value = output
 }
 .dispose()

요 편리한 코드를 그대로 Combine에서 써볼려고 합니다.

 

구현

구현 방식은 각자 다를 것 같은데 원리는 비슷할 것 같아요!

extension Publisher {
  func withUnretained<O: AnyObject>(_ owner: O) -> Publishers.CompactMap<Self, (O, Self.Output)> {
    compactMap { [weak owner] output in
      owner == nil ? nil : (owner!, output)
    }
  }
}

요렇게 Publisher의 Extension으로 작성합니다.

내용은 심플하게 compactMap을 래핑한 Transform으로 해보았습니다. 

이번 경우는 owner에 문제가 생기면 값 자체가 nil로 들어오는 패턴이고 좀더 응용을 해본다면 Error를 발생시키는 식으로 해볼 수 있을 것 같네요!

useCase
  .value
  .withUnretained(self)
  .sink { (owner, output) in
    owner.currentValue = output
  }
.store(in: &cancelablles)

위 처럼 self에 대한 바인딩 없이 subscriber를 자유롭게 사용할 수 있습니다.

Comments