Search code examples
swiftsendcombinepublishersink

My subscriber cannot receive subscription


I have a problem of using combine send and sink method.

the publisher like this

//ViewModel
let reviewCellData = CurrentValueSubject<[ArchivingReviewCellModel], Never>([])

I surely checked the promise(.success) called.

//ViewModel
func fetchArchivingData(page: Int) -> Future<Archiving, Never> {
        return Future<Archiving, Never> { promise in
            //
            
            let task = URLSession.shared.dataTask(with: request) { data, response, error in
                //
                
                do {
                    let decodedData = try JSONDecoder().decode(ArchiveResponseDTO.self, from: data!)
                    let archiving = decodedData.toDomain()
                    print("Promise success")
                    promise(.success(archiving))
                } catch let decodingError {
                    //
                }
            }
            task.resume()
        }
    }

and right after, the reviewCellData send the data.

//ViewModel
func fetchReviewCellData(page: Int) {
        fetchArchivingData(page: page).subscribe(on: utilityQueue)
            .sink(receiveValue: { [weak self] receivedValue in
                guard let self = self else { return }
                if page == 1 {
                    let sendValue = convertToReviewCellModels(from: receivedValue)
                    print("send Now!")
                    self.reviewCellData.send(sendValue)
                } else {
                    let oldValue = self.reviewCellData.value
                    let newValue = oldValue + convertToReviewCellModels(from: receivedValue)
                    self.reviewCellData.send(newValue)
                }
            }).store(in: &bag)
    }

I already set the subscriber using sink

//View
private func setupDataSubscription() {
        print("Setting subscriber")
        viewModel.reviewCellData.sink { [weak self] cellModels in
            print("Receive Now! : \(cellModels)")
            self?.updateUI(with: cellModels)
        }.store(in: &bag)
    }

But after the publisher send data(sendValue), the sink not called. It`s also sure that view has viewModel and already initialized.

enter image description here


Solution

  • None of your sample code shows fetchReviewCellData being called. Without that call none of your pipelines are going to fire. I converted your code to a playground and added a call to fetchReviewCellData and it seems to work without trouble. If there is a problem with your code then it is in areas that you are not showing.

    Here is the playground code I wrote. If you are still not able to solve your issue then you might try boiling it down to a Minimal, Reproducible, example and see if that gives you an insight.

    import UIKit
    import Combine
    
    var greeting = "Hello, playground"
    
    typealias ArchivingReviewCellModel = Int
    var bag = Set<AnyCancellable>()
    
    enum Archiving {
      case yupArchiving
    }
    
    let reviewCellData = CurrentValueSubject<[ArchivingReviewCellModel], Never>([])
    
    func fetchArchivingData(page: Int) -> Future<Archiving, Never> {
      return Future<Archiving, Never> { promise in
        Task {
          try await Task.sleep(nanoseconds: 1 * NSEC_PER_SEC)
          print("Promise success")
          promise(.success(.yupArchiving))
        }
      }
    }
    
    func convertToReviewCellModels(from: Archiving) -> [ArchivingReviewCellModel] {
      return []
    }
    
    let utilityQueue = DispatchQueue.global(qos: .utility)
    func fetchReviewCellData(page: Int) {
      fetchArchivingData(page: page).subscribe(on: utilityQueue)
        .sink(receiveValue: { receivedValue in
          if page == 1 {
            let sendValue = convertToReviewCellModels(from: receivedValue)
            print("send Now!")
            reviewCellData.send(sendValue)
          } else {
            let oldValue = reviewCellData.value
            let newValue = oldValue + convertToReviewCellModels(from: receivedValue)
            reviewCellData.send(newValue)
          }
        }).store(in: &bag)
    }
    
    private func setupDataSubscription() {
      print("Setting subscriber")
      reviewCellData.sink { cellModels in
        print("Receive Now! : \(cellModels)")
      }.store(in: &bag)
    }
    
    setupDataSubscription()
    fetchReviewCellData(page: 3)
    

    output:

    Setting subscriber
    Receive Now! : []
    Promise success
    Receive Now! : []