RxSwift 하나의 구독을 폐기하면 다른 구독의 폐기가 호출됩니다.

Aug 18 2020

나는이 PublishSubject<InfoData>의 ViewController에. 그리고 나는 그것을 구독하므로 이벤트가 발생하면 UIAlertViewController를 표시합니다.

let infoData = PublishSubject<InfoData>()
private func bindInfoData() {
     infoData.subscribe(onNext: { [weak self] (title, message) in
         self?.presentInfoSheetController(with: title, message: message)
     }).disposed(by: disposeBag)
}

ViewController에는 섹션 헤더가있는 tableView가 있습니다. 섹션 헤더보기에는 infoMessageAction: PublishSubject<InfoData?>. 에 대한보기를 시작할 때 와 viewForHeaderInSection사이에 구독을합니다 .infoMessageActioninfoData

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
      let view = FutureSpendingsHeaderView(frame: frame)
      view.infoMessageAction
            .compactMap { $0 }
            .bind(to: infoData)
            .disposed(by: view.disposeBag)
      return view
}

처음으로 시작된 헤더 뷰가 모두 잘 작동 infoMessageAction하면 infoDataAlertViewController의 표시를 트리거하는 을 트리거합니다 . 나는 화면을 넘어 헤더보기를 스크롤하면 사이의 가입 view.infoMessageActioninfoData(뷰가 deinited되면서 예상되는 동작)를 파기합니다.

그러나 infoData나는와 ViewController 사이의 구독도 폐기했습니다 . 나는 수신 event completeddispose대한 view.infoMessageAction<-> infoData가입 및도 event completeddispose대한 infoData<->의 ViewController의 가입이 필요합니다.

view.infoMessageAction<-> infoData구독 만 중단 될 것으로 예상합니다 . 또한 두 구독 모두 다른 disposeBag에 의해 처리됩니다. infoData<-> ViewController 구독이 폐기되는 이유 와이를 방지하는 방법은 무엇입니까?

미리 감사드립니다!

답변

DanielT. Aug 18 2020 at 18:28

FutureSpendingsHeaderView초기화가 해제 되면 소스 인 뷰 infoMessageAction도 초기화 해제되고 해당 뷰 completed는 해당 시점에 이벤트를 생성합니다. 완료된 이벤트가 전달되어 infoData자체 완료된 이벤트를 내 보냅니다.

Observable이 완료된 이벤트를 내 보내면 완료됩니다. 더 이상 이벤트를 생성 할 수 없습니다. 따라서 그것에 대한 구독이 폐기됩니다.

귀하의 답변 @Alex는 뷰 내부의 항목이 초기화되지 않는 순서를 변경하여 방정식을 변경합니다. disposeBag는 이제 먼저 초기화가 해제되고 뷰가 completed 이벤트를 보내기 전에 관찰 가능한 체인이 끊어집니다.

더 나은 솔루션은 사용하는 것 PublishRelay(A)보다 다소을 PublishSubject. 릴레이는 완료된 이벤트를 내 보내지 않습니다.

그것보다 더 나은 것은 주제를 완전히 제거하고 다음과 같은 것을하는 것입니다.

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
    let view = FutureSpendingsHeaderView(frame: frame)
    view.infoMessageAction
        .compactMap { $0 }
        .subscribe(onNext: { [weak self] (title, message) in
            self?.presentInfoSheetController(with: title, message: message)
        })
        .disposed(by: view.disposeBag)
    return view
}
Alex Aug 18 2020 at 16:20

누군가가 그러한 상황에 직면하면 문제를 발견했습니다. 섹션 헤더 뷰에서 나는 disposeBag상수로 시작 했고 뷰가 정의 될 때 다른 모든 것은 RxSwift 자체에서 처리한다고 생각했습니다. 그래서 뷰를 다음과 같이 업데이트했습니다.

var disposeBag = DisposeBag()
    
deinit {
    disposeBag = DisposeBag()
}

이제 구독은 필요에 따라 폐기됩니다.