Problem with Xcode 13.1, SwiftUI, Mapkit and geoJSON - Polygon overlay does not render onto the map

Viewed 25

I am trying to show a geoJSON polygon on my IOS map app. I'm using Xcode 13.1, SwiftUI and following some tutorials have coded the map which works successfully. I am now trying to use a geoJSON file generated at geojson.io to display a polygon on the map, but so far I have been unsuccessful. I've added some print statements to the code and I can see the geoJSON seems to parse and be decoded fine, but the mapView.addOverlays call doesn't seem to be calling the mapView function (no print). If someone wouldn't mind having a look at my code below and point me in the right direction or help me figure out what I'm missing, that would be amazing. Many thanks, Berto.


import UIKit
import MapKit

class ViewController: UIViewController {

    private let locationManager = CLLocationManager()
    private var currentCoordinate: CLLocationCoordinate2D?
    
    
    @IBOutlet var mapView: MKMapView!
    override func viewDidLoad() {
        super.viewDidLoad()
        configureLocationServices()

        // Do any additional setup after loading the view.
    }

    //function to check or request access to the users location while using the app
    private func configureLocationServices() {
        locationManager.delegate = self
        
        let status = CLLocationManager()
        
        if  status.authorizationStatus == .notDetermined {
            locationManager.requestWhenInUseAuthorization()
            
        }   else if status.authorizationStatus == .authorizedWhenInUse {
                beginLocationUpdates(locationManager: locationManager)
            
        }
    }
    
    //function to set GPS accuracy and continually track location on map
    private func beginLocationUpdates(locationManager: CLLocationManager) {
        mapView.showsUserLocation = true
        
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.startUpdatingLocation()
        
    }
    
    //function to set the zoomed area of the map around the current location
    private func zoomToLatestLocation(with coordinate: CLLocationCoordinate2D) {
    
        let zoomRegion = MKCoordinateRegion(center: coordinate, latitudinalMeters: 1000, longitudinalMeters: 1000)
        mapView.setRegion(zoomRegion, animated: true)
        
    }
    
}

extension ViewController: CLLocationManagerDelegate {
    
    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        print("mapView renderer called")
        if overlay is MKPolygon {
            let renderer = MKPolygonRenderer(overlay: overlay)
            renderer.fillColor = UIColor.red
            renderer.strokeColor = UIColor.black
        
            return renderer
        }
        return MKOverlayRenderer()
    }
 
    //function to update users location
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        print("did get latest location")
        
        guard let latestLocation = locations.first else { return }
        
        if currentCoordinate == nil {
            zoomToLatestLocation(with: latestLocation.coordinate)
            print("calling GeoJSON parse function")
            mapView.addOverlays(self.parseGeoJSON())
        }
        
        currentCoordinate = latestLocation.coordinate
    }
    
    func parseGeoJSON() -> [MKOverlay] {
        print("started geoJSON parse")
        guard let url = Bundle.main.url(forResource: "london", withExtension: "json") else {
            fatalError("unable to get geoJSON")
        }
        print("loaded trail1 geoJSON")
        var geoJSON = [MKGeoJSONObject]()
        do {
            let data = try Data(contentsOf: url)
            geoJSON = try MKGeoJSONDecoder().decode(data)
            print("decoded geoJSON")
        } catch {
            fatalError("unable to decode geoJSON")
        }
        var overlays = [MKOverlay]()
        for item in geoJSON {
            if let feature = item as? MKGeoJSONFeature {
                for geo in feature.geometry {
                    if let polygon = geo as? MKPolygon {
                        overlays.append(polygon)
                        print("appended polygon")
                      
                    }
                }
            }
        }
        
        print("returning overlays polygon")
        return overlays

    }
    
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        print("the status changed")
        if status == .authorizedWhenInUse {
            beginLocationUpdates(locationManager: manager)
            
        }
        
    }
}

London.json file generated from geojson.io


{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              -0.2581787109375,
              51.415481636209535
            ],
            [
              -0.078277587890625,
              51.36920841344186
            ],
            [
              0.1153564453125,
              51.46427482966439
            ],
            [
              0.13458251953125,
              51.586456488215426
            ],
            [
              -0.078277587890625,
              51.64358968607138
            ],
            [
              -0.28701782226562494,
              51.613752957501
            ],
            [
              -0.336456298828125,
              51.50703296721856
            ],
            [
              -0.2581787109375,
              51.415481636209535
            ]
          ]
        ]
      }
    }
  ]
}

0 Answers
Related