기어가더라도 제대로

RxSwift 용어 정리 -3- (share, withUnretained) 본문

Swift - 기초

RxSwift 용어 정리 -3- (share, withUnretained)

Damagucci-juice 2022. 5. 12. 16:34

참고 : https://jusung.github.io/shareReplay/   (너무 좋습니다.)
위 블로그 내용 이해하기 위해 필기본입니다. 위에 링크를 보세요.


 

[RxSwift] Share(replay:)

anObservable.share(replay:1) 같은 코드를 보신적 있으실 겁니다. Share 연산자는 언제 써야하는 걸까요?

jusung.github.io

 

1. RxSwift Subscribe()

Observable 은 선언해 놓아도, Subscribe() 되기 전에는 이벤트를 방출하지 않는다. 이는 Observable 에 아무리 많은 연산자를 걸어놓아도, subscribe() 가 호출되기 전까진 아무 동작도 하지 않는다는 뜻이다. 

좀더 정교하게 말하면 Observable 은 subscribe 될 때마다 create 클로저를 호출해 Observable을 생성합니다.

Observable 을 subscribe 할 때마다 새로운 Observable 시퀀스가 생성된다.

 

2. Share()

bind(to:) 는 subscribe() 의 일종인데, subscribe() 가 실행할 수 있는 onEvent의 종류는 3가지(onNext(), onCompleted(), onError) 인 반면에, bind(to:) 는 onNext() 하나의 이벤트만 다룰 수 있다. 결국 bind(to) 를 하면 subscribe().onNext(to:) 를 한 것과 같은 효과가 나는데, subscribe를 할 때마다 새로운 Observable 시퀀스가 생성된다는 말은 API 요청을 할 경우가 있다면 subscribe() 횟수만큼 요청을 한다는 이야기이다. 이 때 share() 를 사용하면 그런 일을 방지 할 수 있다. 

  • share()는 subscribe()가 처음 호출될 때 (Subscriptoin횟수가 0 -> 1 일때)만 Subscription을 생성
    • 두번째 세번째로 subscribe()가 호출되면 새로운 Subscription을 생성하는 것 대신 이미 만들어진 Subscription을 이후 subscribe()를 호출한 곳에 공유해 사용
  • share() 에 subscribe() 한 Subscription 이 모두 disposed 되면 share() 는 공유했던 Subscription 을 dispose 시킨다.
  • 이후 다른 subscribe() 가 호출되면 share() 는 새로운 subscription 을 생성한다. 

Replay 

share(replay: ) 에 들어가는 인자를 뜻한다. 이는 buffer 의 크기이다. 버퍼는 item 이 담길 수 있는 메모리 주소의 크기라고 보면 좋다.

  1. 다른 시퀀스에서 share() 된 Observable 을 구독했을 때
  2. 가장 최근 방출했던 아이템을 버퍼의 크기만큼
  3. 새로운 구독 시퀀스에 전달
public func share(replay: Int = 0, scope: SubjectLifetimeScope = .whileConnected)

share() 의 정의이다. replay 는 위에서 다뤘고, scope 는 buffer 의 생명주기에 관한 인자입니다. 기본으로 .whileConnected 가 들어갑니다. 

buffer 생명주기 정책 2가지

  • .forever: subscription 이 0 이 되더라도 버퍼가 유지된다.
    • 그래서 새로운 Subscription 은 subscribe() 를 하면 마지막에 버퍼에 남아있던 replay 개수 만큼의 값을 수신하게 됩니다.
  • .whileConnected : 1개 이상의 subscriber 가 존재하는 동안만 버퍼가 유지
    • subscription 이 0 이 되었다가 새로운 subscription 이 등록되면 새값을 요청해 수신하게 됩니다. 

share() 는 속에선 어떨까? 

사실 Rx 공홈에서 Share 항목을 검색해서 찾아들어가면 바로 refCount 항목으로 이동합니다. 

사실은 이렇습니다. anObservable.share() 는 anObserable.publish().refCount() 입니다. 

  • publish() : 이 연산자는 보통의 Observable 을 ConnectableObservable 로 변환해줍니다. 
  • ConnectableObservable :  subscriber 가 있어도 해당 Observable 의 connect() 메서드를 호출하기 전까지는 아이템을 방출 하지 않습니다. 
  • refcount() : ConnectableObservable 에 Connect와 Disconnect를 자동으로 담당하고, ConnectableObservable 을 보통의 Observable 처럼 사용할 수 있게 해줍니다. Subscription count를 계속 세고 있다가 Subscription 의 개수가 0 -> 1 개가 되는 시점에 connect() 를 수행하고, subscription 이 0 이되면 disconnect() 를 수행합니다. 

 

withUnretained()

비동기 콜백 핸들러를 사용할 때 클로저로 되어 있어서 자기 자신 객체를 찾게 될 일이 있을 경우, self 라는 키워드를 사용한다. 근데 이렇게 self 를 사용할 경우 메모리 누수의 위험이 있어서 보통은 

이런 식으로 사용을 한다. 이걸 rx swift 에서 깔끔하게 정리하기 위해서 withUnretained() 라는 오퍼레이터를 준비해주었다. 

사용법 

 

Comments