[RxSwift] Observable의 생명 주기, 순환 참조와 메모리 관리, subscribeOn, observeOn
iOS/Swift

[RxSwift] Observable의 생명 주기, 순환 참조와 메모리 관리, subscribeOn, observeOn

정말 생초보,, 아무것도 모르는 입장에서 강의 영상을 보고 의식의 흐름대로 작성한 글이니 비판의 눈으로 글을 읽어 주시면 감사하겠습니다~~ 오류 지적 대환영!

Observable Life-Cycle


1. Create

  • Observable 생성
  • 데이터가 생성되거나, 어떤 명령이 동작하지 않음 → 2. Subscribe에서 동작!

2. Subscribe

  • 어떠한 Observable이 동작함

3. Next

  • 데이터 전달

4. Completed

  • 정상적으로 동작 끝

4-1. Error

  • 비정상적으로 동작 끝

5. Disposed

  • Dispose되면 그 Observable은 더 이상 재사용 불가

.debug() 로 Observable 상태 확인 가능

순환 참조와 메모리 관리


.subscribe(onNext: { i in
    self.countLabel.text = "\(i)"
})
.disposed(by: disposeBag)

이 코드에서 subscribe 내에서 UI 작업을 하느라 self(ViewController)를 참조. 이미 VC 인스턴스를 생성하면서 한 번 참조된 것임. VC가 pop 되더라도 위 클로저에서 한 번 참조된 게 남아 있음! (4번의 RC=1) 이 VC 인스턴스는 더 이상 안 쓰는데...→ 순환 참조에 의한 메모리 누수(Memory Leak)

메모리 누수를 해결하려면 약한 참조(weak self)를 사용하거나, onCompleted()를 통해 Subscribe 클로저 자체를 종료시킨다.

  • 약한 참조(weak self)
.subscribe(onNext: { [weak self] i in
    self.countLabel.text = "\(i)"
})
.disposed(by: disposeBag)

weak self를 안 썼을 때는 자동으로 강한 참조(strong)로 사용됨. weak self는 위의 코드와 같이 사용하며, 참조될 때 RC를 증가시키지 않는다! 상위 인스턴스가 해제되면(RC- -) 얘는 바로 메모리에서 날아감(RC=0).

  • subscribe의 클로저를 종료시키는 또 다른 방법: Observable을 만들 때 onCompleted() 명시
emitter.onNext(image)
emitter.onCompleted()
return Disposables.create()

뭐 이런 식으로... onCompleted가 꼭 실행되도록 명시하면 Observable 동작 자체가 종료되면서 메모리가 해제됨.

스레드 분기


  • DispatchQueue, OperationQueue를 사용하는 대신 observeOn, subscribeOn을 사용함! (DispatchQueue, OperationQueueobserveOn, subscribeOn가 감싼(wrapping) 개념)

subscribeOn

  • 한 번만 사용 가능, 구독 시 시작할 스레드 지정
  • subscribeOn이 지정된 위치에 상관없이 첫 스레드를 지정함!
  • 위에 있는 Stream에 영향을 줌 → 업스트림(Up Stream)

observeOn

  • 여러 번 사용 가능, observeOn에서 스레드를 지정한 후 그 아래부터의 Stream에 작동 → 다운스트림(Down Stream)

Stream의 분리 및 병합


merge

  • Observable 2개를 1개로 merge
  • 하나로 합쳐야 하기 때문에 데이터 타입을 통일해야 함!

zip

  • 쌍으로 만들어 전달 → 데이터 타입 달라도 상관 X
1----2--------3---------4---->
B----------C---A------------->
########### zip ############
1B---------2C--3A------------>
  • 데이터의 개수는 가장 작은 스트림의 데이터 개수와 동일!

combineLatest

  • zip과의 차이점: 가장 최근의 데이터와 쌍을 이뤄 전달
1----2--------3---------4---->
B----------C---A------------->
######### combineLatest #########
1B---2B----C2-3C--A3----4A--->

Reference