CombineLatest от Swift Combine не запускается в ответ на обновление одного из его издателей - PullRequest
0 голосов
/ 25 марта 2020

Я объединяю двух издателей, чтобы определить, какой должна быть центральная координата вида карты. Два издателя:

  1. Исходное местоположение пользователя, определяемое CLLocationManager (первое местоположение, сообщаемое после того, как CLLocationManager начинает отправку обновлений местоположения).
  2. Текущее местоположение пользователя если нажата кнопка «Центральная карта на текущем местоположении».

В коде:

    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
        }

        //...

    }

Оба издателя, $initialUserCoordinate и centerButtonTappedPublisher, обновления publi sh - Я это подтвердил. Однако объединенный издатель coordinatePublisher срабатывает только при нажатии кнопки «Карта центра в текущем местоположении». Он никогда не срабатывает, когда впервые устанавливается свойство initialUserCoordinate.

Этот вопрос предлагает добавить .receive(on: RunLoop.main) после Publishers.CombineLatest($initialUserCoordinate, centerButtonTappedPublisher), но у меня это не работает.

Что я делаю не так?

1 Ответ

1 голос
/ 25 марта 2020

Вам необходимо использовать Publishers.Merge вместо CombineLatest, см. Документацию:

Для Publishers.CombineLatest:

Издатель, который получает и объединяет последние элементы от двух издателей.

Для Publishers.Merge

Издатель, который генерирует событие, когда либо вышестоящий издатель отправляет событие.

...