[Combine] - 중복되는 Subscriber를 방지하기

Ben·2023년 8월 17일
0

iOS

목록 보기
6/23

Trouble-shooting 💥

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을 사용하여 이전 구독을 추적하고 취소하며, 새로운 구독을 추가한다.


이와 같이 로직을 수정해주면 중복 구독의 문제는 해결이 가능하다.

profile
 iOS Developer

1개의 댓글

comment-user-thumbnail
2023년 8월 17일

좋은 글 감사합니다. 자주 올게요 :)

답글 달기