nayem
nayem

Reputation: 7605

Loading data from api and showing annotation after MKMapView's region is successfully set to user's current location

I have an MKMapView where I'm showing annotations and the location informations are coming from an API. I've added a button which will trigger getting data from the API and showing corresponding annotations in the map view. However, I'm trying to implement such thing:

User lands on the map view scene and the current location gets updated and the region of the map view is set to a specific boundary around the user's location. After the animation for .setRegion(_:animated:) of the map view completes, some annotations will be shown to user without the user specifically tapping the button for showing annotation.

But after going through different delegate methods of CLLocationManagerDelegate and MKMapViewDelegate, I couldn't find any useful solution to my requirement. Sometimes the annotations are added before the animation for region setting completes. Sometimes they are added after the animation completes.

I've used CLLocationManger for getting the user's current location. From the locationManager(_:didUpdateLocations:) delegate method I'm setting the region for map view:

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    guard let location = locations.last else { return }
    let span = MKCoordinateSpanMake(0.05, 0.05)
    let region = MKCoordinateRegion(center: location.coordinate, span: span)
    mapView.setRegion(region, animated: true)
    mapView.showsUserLocation = true

    // Remove activity indicator
    effectView.removeFromSuperview()

    // This method is responsible for getting location information from the api and adding annotations to the map view
    findPlaces(withType: "restaurant")
}

In the above delegate method, I'm calling findPlaces(withType:) method which will fetch data from API and add annotations to the map. The API needs a location and a radius for sending data back.

In my mapView(_:regionDidChangeAnimated:) delegate, I'm keeping track of the center position and visible area of the map view which I'll use later when user taps on the Show Here button.

func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {

    let visibleMapRect = mapView.visibleMapRect
    let leftMapPoint = MKMapPointMake(MKMapRectGetMinX(visibleMapRect), MKMapRectGetMidY(visibleMapRect))
    let rightMapPoint = MKMapPointMake(MKMapRectGetMaxX(visibleMapRect), MKMapRectGetMidY(visibleMapRect))

    mapViewDistance = MKMetersBetweenMapPoints(leftMapPoint, rightMapPoint)
    mapViewCenter = mapView.centerCoordinate
}

How to show annotations to the user automatically after map view's center is set to the user's current location and the viewable region of the map view is done setting with animation?

This is the nearly expected output:

This is not the output I want:

Edit:

Here is how the findPlaces(withType:) is implemented:

func findPlaces(withType: String?) {

    // preparing an url from the passed string here
    queryURL = ...

    // get the json data asynchronously
    DataManager.loadData(from: queryURL) { (data, error) in

        if let error = error {
            // Handled error case
        } else {
            do {
                guard let data = data else {
                    // throw error
                }
                let json = try JSONSerialization.jsonObject(with: data, options: [])
                guard let placesDictionary = json as? JSON else {
                    // throw error
                }
                guard let places = Places(json: placesDictionary) else {
                    // throw error
                }
                guard let results = places.results else {
                    // throw error
                }

                // data is fed into results array, now plot this into the map view
                // UI Update should be on the main thread
                DispatchQueue.main.async {
                    self.plotPlaces(with: results)
                }
            } catch {
                print(error)
            }
        }
    }
}

Upvotes: 0

Views: 1011

Answers (1)

Shubham
Shubham

Reputation: 773

Try getting location information and setting annotation in func mapView(MKMapView, regionDidChangeAnimated: Bool) method

func mapView(MKMapView, regionDidChangeAnimated: Bool) {

// This method is responsible for getting location information from the api and adding annotations to the map view.
findPlaces(withType: "restaurant")

}

Upvotes: 0

Related Questions