edulpn
edulpn

Reputation: 125

RxSwift Driver calling twice on first time

I have a CoreLocation manager that should handle all CLLocationManager by offering observable properties through RxSwift (and its Extensions and DelegateProxies). LocationRepository looks like this:

class LocationRepository {
    static let sharedInstance = LocationRepository()
    var locationManager: CLLocationManager = CLLocationManager()
    private (set) var supportsRequiredLocationServices: Driver<Bool>
    private (set) var location: Driver<CLLocationCoordinate2D>
    private (set) var authorized: Driver<Bool>

    private init() {
        locationManager.distanceFilter = kCLDistanceFilterNone
        locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation

        supportsRequiredLocationServices = Observable.deferred {
            let support = CLLocationManager.locationServicesEnabled() && CLLocationManager.significantLocationChangeMonitoringAvailable() && CLLocationManager.isMonitoringAvailable(for:CLCircularRegion.self)
            return Observable.just(support)
        }
        .asDriver(onErrorJustReturn: false)

        authorized = Observable.deferred { [weak locationManager] in
            let status = CLLocationManager.authorizationStatus()
            guard let locationManager = locationManager else {
                return Observable.just(status)
            }
            return locationManager.rx.didChangeAuthorizationStatus.startWith(status)
        }
        .asDriver(onErrorJustReturn: CLAuthorizationStatus.notDetermined)
        .map {
            switch $0 {
            case .authorizedAlways:
                return true
            default:
                return false
            }
        }

        location = locationManager.rx.didUpdateLocations.asDriver(onErrorJustReturn: []).flatMap {
            return $0.last.map(Driver.just) ?? Driver.empty()
        }
        .map { $0.coordinate }
    }

    func requestLocationPermission() {
        locationManager.requestAlwaysAuthorization()
    }
}

My presenter then listens to changes on the repository properties. LocatorPresenter looks like this:

class LocatorPresenter: LocatorPresenterProtocol {
    weak var view: LocatorViewProtocol?
    var repository: LocationRepository?
    let disposeBag = DisposeBag()

    func handleLocationAccessPermission() {
        guard repository != nil, view != nil else {
            return
        }

        repository?.authorized.drive(onNext: {[weak self] (authorized) in
            if !authorized {
                print("not authorized")
                if let sourceView = self?.view! as? UIViewController, let authorizationView = R.storyboard.locator.locationAccessRequestView() {
                    sourceView.navigationController?.present(authorizationView, animated: true)
                }
            } else {
                print("authorized")
            }
        }).addDisposableTo(disposeBag)
    }
}

It does work, but I'm getting the Driver calling twice for the first time I try to get the authorization status, so the access request view gets presented twice. What am I missing here?

Regards!

Upvotes: 0

Views: 2419

Answers (1)

xandrefreire
xandrefreire

Reputation: 2326

From startWith documentation:

StartWith emit a specified sequence of items before beginning to emit the items from the source Observable

I have not tried it, but probably if you remove startWith(status) you won't receive the status twice.

It seems you are receiving the next sequence from the observable:

---------------------------------unauthorized----authorized----->

So with the line:

startWith(status) // status is unauthorized

you finally get this one:

-------unauthorized---------unauthorized----authorized----->

Upvotes: 1

Related Questions