본문 바로가기

iOS_RxSwift

Subject, Relay 에 대한 활용 및 이해도 정리

오늘은 프로젝트에서 사용했던, RxSwift 에서 PublishRelay, PublishSubject, BehaviorRelay, BehaviorSubject 에 관한 내용을 정리해보고자 한다.

 

관련 내용들은 진행했던 프로젝트에서 cmd+C,V 하여 사용했던 것을 토대로 개인적인 이해도를 정리하였으며, 관련 전문성은 현재로선 떨어지는 부분이지만 지금까지 이해한 정도를 정리하고, 추후 보완해 나갈 예정이다.

 

우선 현재까지 이해한 정도로 정리하자면

BehaviorRelay<T> 는 ObservableType이고 이는 ObservableConvertibleType 으로써 Observable<Element> 객체를 쉽게 들고 다니며 초기화, get, set, 변수로서 저장 용도로 사용할수 있는 클래스이다.

⇒ 결국 BehaviorSubject 라는 Observable<Element> 를 초기화, get, set, 변수로서 저장한다고 생각

 

PublishRelay<T> 역시 비슷한 개념인데, 살짝 다르다.

PublishRelay<T> 는 .accept를 통한 set 작업과 .asObservable의 Observable<Element> 형태로만 get 할수 있는 반면,

BehaviorRelay<T> 는 .accept를 통한 set 작업과 .asObservable의 Observable<Element> 형태로의 get 외에 .value 작업을 통해 Observable<Element> 의 Element 도 get 할 수 있다.

 

CocoaPods SwinjectAutoregistration 에 정리했던 ApiServiceType interface 를 토대로 사용 샘플코드를 정리해본다.

import RxSwift

protocol ApiServiceType {
  var currentUser: User? { get }
  var currentUserObservable: Observable<User?> { get }
  // User 는 고객정보를 담은 객체 

  func requestLogin(password: String)
}

protocol interface 에서는 선언과 { get } 만!

아래 구현부 코드에서 프로토콜과 같이 사용한 코드를 정리한다.

final class ApiService: ApiServiceType {
  private var _currentUser = BehaviorRelay<User?>(value: nil) // 초기화
  // 원시 타입은 이런식으로 초기화 가능 → BehaviorRelay<Int>(value: 0)
  
  var isLogged: Bool {
    _currentUser.value != nil
  }

  var currentUser: User? {
    _currentUser.value // value로 get
    // 만약 _currentUser 가 PublishRelay 였다면 이런식의 get은 불가능하다.
  }
  
  var currentUserObservable: Observable<User?> {
    _currentUser.asObservable()
  }
  
  func requestLogin(password: String) {
    // 관련 서버에 사용자의 password입력을 받아, 사용자 정보를 받아왔다고 가정.
    let user = User()
    _currentUser.accept(user) // accept로 값 set
  }
}

이런식으로 BehaviorRelay와 ApiServiceType 프로토콜 인터페이스와 구현부를 선언해놓으면

다른 클래스에서 SwinjectAutoregistration 을 통해 손쉽게 사용할 수 있다.

RIBs 아키텍처를 사용하는 경우의 사용 예제는 RIBs + ReactorKit 뼈대 정리를 참고하자.

import RxSwift
import UIKit
import SwinjectAutoregistration

class SampleViewController: UIViewController {
  private var apiService: ApiServiceType
  
  init() {
    self.apiService = container ~> ApiServiceType.self
  }
  
  required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
  
  override func viewDidLoad() {
    if apiService.currentUser == nil {
      // 비로그인 상태
    } else {
      // 로그인 상태
    }
  }
  
}

PublishRelay를 사용하는 예제는 추후 정리할 예정이다.