Reactive Programming in iOS with Combine, Episode 27: Scheduling Operators | Kodeco, the new raywenderlich.com

Learn about the schedule and receive operators, which can be used to tell Combine which Scheduler to use when running the operations.


This is a companion discussion topic for the original entry at https://www.kodeco.com/5429795-reactive-programming-in-ios-with-combine/lessons/27

I’ve been experimenting with different options for subscribing on one scheduler and receiving events on another and came across behaviour that I cannot explain. Could somebody help me out?

This code compiles fine:

var subscriptions = Set<AnyCancellable>()

let computationPublisher = Publishers.ExpensiveComputation(duration: 3)

let queue = DispatchQueue(label: "serial queue")

let currentThread = Thread.current.number
print("Start computation publisher on thread \(currentThread)")

computationPublisher
  .subscribe(on: queue)
  .receive(on: DispatchQueue.main)
  .map { $0 } // <- This map doesn't do anything
  .map { $0 } // <- This map doesn't do anything either
  .sink { value in
    let thread = Thread.current.number
    print("Received computation: \(value) on thread: \(thread)")
  }
  .store(in: &subscriptions)

But if I try printing something from the second map I’m getting a type inference error.

computationPublisher
  .subscribe(on: queue)
  .receive(on: DispatchQueue.main)
  .map { $0 } // <- This map doesn't do anything
  .map { value in
    print("Observed value: \(value)") // <- Adding this print statement throws an error
    // Unable to infer type of a closure parameter 'value' in the current context
    return value
  }
  .sink { value in
    let thread = Thread.current.number
    print("Received computation: \(value) on thread: \(thread)")
  }
  .store(in: &subscriptions)

Removing the first map fixes the error, this code compiles:

computationPublisher
  .subscribe(on: queue)
  .receive(on: DispatchQueue.main)
  .map { value in
    print("Observed value: \(value)")
    return value
  }
  .sink { value in
    let thread = Thread.current.number
    print("Received computation: \(value) on thread: \(thread)")
  }
  .store(in: &subscriptions)

These kind of errors can get rather frustrating :confused:

Thank you for your help!

While it’s not an answer to the question, I found that I can workaround the problem by telling the compiler what I want the return type of anonymous closures to be

computationPublisher
  .subscribe(on: queue)
  .receive(on: DispatchQueue.main)
  .map { $0 }
  .map { value -> String in // <- This map will return a string.
    print("Observed value: \(value)")
    return value
  }
  .sink { value in
    let thread = Thread.current.number
    print("Received computation: \(value) on thread: \(thread)")
  }
  .store(in: &subscriptions)

This compiles again, so that should be enough for me to keep going.

Also, I found this article to be helpful: Tricks and Tips

1 Like