I am combining two publishers to determine what the center coordinate of a map view should be. The two publishers are:
- The user's initial location determined by a
CLLocationManager(the first location reported once theCLLocationManagerbegins sending location updates). - The user's current location if the "center map on current location" button is tapped.
In code:
class LocationManager: NSObject, ObservableObject {
// The first location reported by the CLLocationManager.
@Published var initialUserCoordinate: CLLocationCoordinate2D?
// The latest location reported by the CLLocationManager.
@Published var currentUserCoordinate: CLLocationCoordinate2D?
// What the current map view center should be.
@Published var coordinate: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: 42.35843, longitude: -71.05977) // Default coordinate.
// A subject whose `send(_:)` method is being called elsewhere every time the user presses a button to center the map on the user's location.
var centerButtonTappedPublisher: PassthroughSubject<Bool, Never> = PassthroughSubject<Bool, Never>()
// The combined publisher that is where all my troubles lie.
var coordinatePublisher: AnyPublisher<CLLocationCoordinate2D, Never> {
Publishers.CombineLatest($initialUserCoordinate, centerButtonTappedPublisher)
.map { initialCoord, centerButtonTapped in
var latestCoord = initialCoord
if centerButtonTapped {
latestCoord = self.currentUserCoordinate
}
return latestCoord
}
.replaceNil(with: CLLocationCoordinate2D(latitude: 42.35843, longitude: -71.05977))
.eraseToAnyPublisher()
}
private var cancellableSet: Set<AnyCancellable> = []
//... Other irrelevant properties
private override init() {
super.init()
coordinatePublisher
.receive(on: RunLoop.main)
.assign(to: \.coordinate, on: self)
.store(in: &cancellableSet)
//... CLLocationManager set-up
}
}
extension LocationManager: CLLocationManagerDelegate {
//...
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// We are only interested in the user's most recent location.
guard let location = locations.last else { return }
let latestCoord = location.coordinate
if initialUserCoordinate == nil {
initialUserCoordinate = latestCoord
}
currentUserCoordinate = latestCoord
}
//...
}
Both publishers, $initialUserCoordinate and centerButtonTappedPublisher, publish updates - I have confirmed this. However, the combined publisher coordinatePublisher only fires when the "center map on current location" button is tapped. It never fires when the initialUserCoordinate property is first set.
This question suggests adding a .receive(on: RunLoop.main) after the Publishers.CombineLatest($initialUserCoordinate, centerButtonTappedPublisher) but this does not work for me.
What am I doing wrong?