Environment
- OS: macOS Monterey 12.0.1
- Xcode: 13.1
Context & Issue
I'm implementing a feature which calls an API to fetch new data as an observed value changes. In order to avoid too many API calls, I tried throttling the observed value publisher. But I found this throttling doesn't work if I apply the .eraseToAnyPublisher() method to the publisher.
After some investigation by myself, I noticed the .eraseToAnyPublisher() causes many unnecessary subscriptions and unsubscriptions to the throttled publisher. So I'm wondering if I make any mistakes and would like to get helps.
Minimal reproducible example
import SwiftUI
@main
struct SwiftUITestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
class ViewModel: ObservableObject {
@Published var value: Float = 0
}
struct ContentView: View {
@StateObject private var viewModel = ViewModel()
@State private var text = ""
var body: some View {
VStack {
Text(text)
Slider(value: $viewModel.value, in: 0...1)
}
.padding()
.onReceive(
viewModel
.$value
// .eraseToAnyPublisher() // Uncomment this line causes the issue
.throttle(for: 1, scheduler: DispatchQueue.main, latest: true)
.print()
) { value in
text = String(format: "%.2f", arguments: [value])
}
}
}
Behavior without .eraseToAnyPublisher()
If I don't apply .eraseToAnyPublisher(), this code works as expected and the .print() of the publisher will output something like:
receive subscription: (Throttle)
request unlimited
request unlimited
receive value: (0.0)
receive cancel
receive subscription: (Throttle)
request unlimited
request unlimited
receive value: (0.0)
receive value: (0.021933686)
receive value: (0.28136003)
receive value: (0.6122359)
receive value: (0.66554797)
receive value: (0.3587148)
receive value: (0.2890992)
Behavior with .eraseToAnyPublisher()
If I apply .eraseToAnyPublisher(), the throttled publisher gets subscribed and unsubscribed many times. This makes the throttling look not working. The .print() of the publisher will output something like:
receive subscription: (Throttle)
request unlimited
request unlimited
receive value: (0.0)
receive cancel
receive subscription: (Throttle)
request unlimited
request unlimited
receive value: (0.0)
receive cancel
receive subscription: (Throttle)
request unlimited
request unlimited
receive value: (0.12430311)
receive cancel
receive subscription: (Throttle)
request unlimited
request unlimited
receive value: (0.12430311)
receive cancel
receive subscription: (Throttle)
request unlimited
request unlimited
receive value: (0.13761736)
receive cancel
receive subscription: (Throttle)
Question
Though I've already found a workaround (= not using .eraseToAnyPublisher()), I would like to understand why this happens. In my understanding, .eraseToAnyPublisher() only erases the type information and should not cause any behavioral changes.
Thanks