Trouble-shooting이라고 하기엔 애매하지만, 새로운 문제를 발견했다.
extension HomeViewController: UITableViewDataSource, UITableViewDelegate, CollectionViewTableViewCellDelegate {
// 생략
// MARK: - CollectionViewTableViewCellDelegate - (Required) Method -> Implementation
func collectionViewTableViewCellDidTapCell(_ cell: CollectionViewTableViewCell, viewModel: Any, title: String?) -> Void {
let previewVC: PreviewViewController = PreviewViewController()
addSubscriptionToYouTubeVMProp(value: title ?? "")
self.youTubeViewModel.youTubeView
.receive(on: DispatchQueue.main)
.sink { completion in
switch completion {
// 생략
}
} receiveValue: { [weak self] video in
previewVC.configurePreview(with: viewModel, video: video)
print("===== (video) - receiveValue =====")
print(video)
print("============================== \n")
}.store(in: &cancellables)
self.navigationController?.pushViewController(previewVC, animated: true)
}
// MARK: - Add Subscription To PassthroughSubject (-> YouTubeViewModel Prop)
private func addSubscriptionToYouTubeVMProp(value: String) -> Void {
APICaller.shared.fetchVideoFromYouTubeWithCombine(with: value)
.sink { completion in
switch completion {
// 생략
}
} receiveValue: { [weak self] youTubeDataResponse in
self?.youTubeViewModel.youTubeView.send(youTubeDataResponse.items[0])
}.store(in: &cancellables)
}
}
collectionViewTableViewCellDidTapCell()은 Parameter인 title을 이용해 addSubscriptionToYouTubeVMProp()으로
PassthroughSubject<Output, Never> 타입의 인스턴스 프로퍼티에 데이터를 전달한 뒤,
그 프로퍼티를 구독하여 받은 값을 previewVC로 넘어가면서 전달해주고 있다.
❗ .store(in: &cancellables)의
cancellables
변수는 HomeViewController의 인스턴스 프로퍼티로 선언 및 초기화가 되어있다.
이 과정에서 중복구독 이슈가 발생하고 있었다.
위 이미지가 중복구독이 되어버린 결과인데
첫번째 cell을 두 번 눌렀을 때, 우측 이미지와 같이 이전의 값을 포함한 결과가 또 한번 출력되고 있었다.
.store(in:)
으로 구독 해제를 해주었음에도 중복구독이 발생한 이유는..
ViewModel의 프로퍼티를 구독하고 값을 받아오는 시점이 끝난 다음인
self.navigationController?.pushViewController(previewVC, animated: true)
이 부분 때문이었다.
UINavigationController는 Stack 기반으로 동작하기 때문에,
힙 영역에 저장되고, stack 구조로 데이터를 저장한다.
즉, ViewMode의 프로퍼티를 구독하는 시점 자체가 HomeVC 이기 때문에 ViewController가 previewVC로 이전되어도
'스택에는 HomeVC가 아직 활성화 되어있어 .store(in: &cancellables)
가 작동하기 않은 것' 이었다.
이 문제의 해결은
class HomeViewController: UIViewController {
// 생략
private var cancellable: AnyCancellable?
}
func collectionViewTableViewCellDidTapCell(_ cell: CollectionViewTableViewCell, viewModel: Any, title: String?) -> Void {
let previewVC: PreviewViewController = PreviewViewController()
cancellable?.cancel()
addSubscriptionToYouTubeVMProp(value: title ?? "")
cancellable = self.youTubeViewModel.youTubeView
.receive(on: DispatchQueue.main)
.sink { completion in
switch completion {
// 생략
}
} receiveValue: { [weak self] video in
previewVC.configurePreview(with: viewModel, video: video)
}
self.navigationController?.pushViewController(previewVC, animated: true)
}
즉, HomeVC의 인스턴스 프로퍼티로 cancellable 변수를 선언해주고
cancellable을 사용하여 이전 구독을 추적하고 취소하며, 새로운 구독을 추가한다.
이와 같이 로직을 수정해주면 중복 구독의 문제는 해결이 가능하다.
좋은 글 감사합니다. 자주 올게요 :)