0

I have several datataskpublisher, which performs requests to the server, from different application screens. How to make them run serial?

Below will be a rough example

This is a service that performs requests and additional logic.

class Service {

   var cacheResult: Data?
   var cacnellable: AnyCancellable?
   static let shared = Service()


   func performPost() -> AnyPublisher<Data, URLError> {
      let task = URLSession.shared.dataTaskPublisher(for: URL(string: "postURL")!)
         .map { (data, _) in data}
         .multicast(subject: PassthroughSubject())

      cacnellable = task.eraseToAnyPublisher().sink(
         receiveCompletion: {_ in },
         receiveValue: { data in
            self.cacheResult = data
         })

      return task.autoconnect().eraseToAnyPublisher()
   }

   func performGet() -> AnyPublisher<Data, URLError> {
      let task = URLSession.shared.dataTaskPublisher(for: URL(string: "getURL")!)
         .map { (data, _) in data}
         .multicast(subject: PassthroughSubject())

      cacnellable = task.eraseToAnyPublisher().sink(
         receiveCompletion: {_ in },
         receiveValue: { data in
            self.cacheResult = data
         })

      return task.autoconnect().eraseToAnyPublisher()
   }

}

This is views

final class GetVC: UIViewController {

   let service = Service.shared
   var cancellable: AnyCancellable?

   override func viewWillAppear(_ animated: Bool) {
      super.viewWillAppear(true)
      cancellable = service.performGet()
         .sink(receiveCompletion: {_ in},
               receiveValue: { data in
                  print("Present data")
               })
   }

}
final class PostVC: UIViewController {

   let service = Service.shared
   var cancellable: AnyCancellable?

   lazy var button: UIButton = {
      let btn = UIButton(primaryAction: UIAction(handler: { _ in
         self.cancellable = self.service.performPost()
            .sink(receiveCompletion: {_ in },
                  receiveValue: { data in
                     print("Some logic")
                  })
      }))
      return btn
   }()
}

I need that requests never went to the server in parallel

If "post task" finished , "get task" start

Thank you!

1 Answers1

0

I came with this decision

class Service {

   var cacheResult: Data?

   var cancellables = Set<AnyCancellable>()

   var taskSubject = PassthroughSubject<AnyPublisher<Data, URLError>, Never>()
   var taskInProcess: Bool = false
   var tasks: [AnyPublisher<Data, URLError>] = [] {
      didSet {
         if !taskInProcess, let firstTask = tasks.first {
            taskInProcess = true
            taskSubject.send(firstTask)
         }
      }
   }
   static let shared = Service()


   init() {

      taskSubject
         .flatMap { $0 }
         .sink(receiveCompletion: { _ in },
               receiveValue: { _ in
                  self.taskInProcess = false
                  self.tasks.removeFirst()
               })
         .store(in: &cancellables)

   }

   func performPost() -> AnyPublisher<Data, URLError> {
      let task = URLSession.shared.dataTaskPublisher(for: URL(string: url)!)
         .map { (data, _) in data}
         .multicast(subject: PassthroughSubject())

      tasks.append(task.autoconnect().eraseToAnyPublisher())

      return task.eraseToAnyPublisher()
   }

   func performGet() -> AnyPublisher<Data, URLError> {
      let task = URLSession.shared.dataTaskPublisher(for: URL(string: url)!)
         .map { (data, _) in data}
         .multicast(subject: PassthroughSubject())

      tasks.append(task.autoconnect().eraseToAnyPublisher())

      return task.eraseToAnyPublisher()
   }

}