title: Swift 5 Parse multi level JSON
body: <p>I am still learning, so any help would be much appreciated.
  I am trying to parse a JSON file, I can't seem to make it work. Followed some online tutorials but I can't find one for this kind of json tree.</p>
  <p>Here is the structure of the json:</p>
  <pre><code>{
      &quot;type&quot;: &quot;FeatureCollection&quot;,
      &quot;features&quot;: [
          {
              &quot;type&quot;: &quot;Feature&quot;,
              &quot;id&quot;: &quot;zone_restrictionate_uav.2120&quot;,
              &quot;geometry&quot;: {
                  &quot;type&quot;: &quot;Polygon&quot;,
                  &quot;coordinates&quot;: [
                      [
                          [
                              24.98812963,
                              44.10877275
                          ],
                          [
                              24.98806588,
                              44.1070722
                          ],
                          [
                              24.98537796,
                              44.10717296
                          ],
                          [
                              24.9854417,
                              44.10887351
                          ],
                          [
                              24.98812963,
                              44.10877275
                          ]
                      ]
                  ]
              },
              &quot;geometry_name&quot;: &quot;the_geom&quot;,
              &quot;properties&quot;: {
                  &quot;zone_id&quot;: &quot;RZ 2120&quot;,
                  &quot;human_readable_definition&quot;: &quot;POLYGON: 440631.5819N 0245917.2667E- 440625.4599N 0245917.0372E- 440625.8227N 0245907.3606E- 440631.9446N 0245907.5901E- 440631.5819N 0245917.2667E&quot;,
                  &quot;wkt&quot;: &quot;POLYGON((24.9881296281 44.1087727458,24.9880658794 44.1070721972,24.9853779561 44.1071729596,24.9854417047 44.1088735083,24.9881296281 44.1087727458))&quot;,
                  &quot;lower_lim&quot;: &quot;GND&quot;,
                  &quot;upper_lim&quot;: &quot;120m AGL&quot;,
                  &quot;contact&quot;: &quot;mailto: aerofoto@mapn.ro&quot;,
                  &quot;status&quot;: &quot;RESTRICTED&quot;
              }
          },
          {
              &quot;type&quot;: &quot;Feature&quot;,
              &quot;id&quot;: &quot;zone_restrictionate_uav.2121&quot;,
              &quot;geometry&quot;: {
                  &quot;type&quot;: &quot;Polygon&quot;,
                  &quot;coordinates&quot;: [
                      [
                          [
                              26.44760265,
                              44.13453494
                          ],
                          [
                              26.43440247,
                              44.11089351
                          ],
                          [
                              26.38955244,
                              44.1359355
                          ],
                          [
                              26.40275262,
                              44.15957693
                          ],
                          [
                              26.44760265,
                              44.13453494
                          ]
                      ]
                  ]
              },
              &quot;geometry_name&quot;: &quot;the_geom&quot;,
              &quot;properties&quot;: {
                  &quot;zone_id&quot;: &quot;RZ 2121&quot;,
                  &quot;human_readable_definition&quot;: &quot;POLYGON: 440804.3258N 0262651.3695E- 440639.2166N 0262603.8489E- 440809.3678N 0262322.3888E- 440934.4769N 0262409.9094E- 440804.3258N 0262651.3695E&quot;,
                  &quot;wkt&quot;: &quot;POLYGON((26.4476026463 44.1345349397,26.4344024672 44.1108935127,26.3895524427 44.1359355018,26.4027526218 44.1595769288,26.4476026463 44.1345349397))&quot;,
                  &quot;lower_lim&quot;: &quot;GND&quot;,
                  &quot;upper_lim&quot;: &quot;120m AGL&quot;,
                  &quot;contact&quot;: &quot;mailto: aerofoto@mapn.ro&quot;,
                  &quot;status&quot;: &quot;RESTRICTED&quot;
              }
          }
      ],
      &quot;totalFeatures&quot;: 339,
      &quot;numberMatched&quot;: 339,
      &quot;numberReturned&quot;: 339,
      &quot;timeStamp&quot;: &quot;2021-08-15T11:39:26.055Z&quot;
  }
  </code></pre>
  <p>I am trying to get the coordinates from the geometry tree level, as well as the data from the properties level, that I will use to annotate a map. But until then I just need to print those informations.</p>
  <p>So far I have the following structs and func:</p>
  <pre><code>struct Notam: Decodable {
      let type: String
      let features: [Feature]
      let totalFeatures: Int
      let numberMatched: Int
      let numberReturned: Int
      let timeStamp: String
  }
  
  struct Feature: Decodable {
      let type: String
      let id: String
      let geometry: [Geometry]
      let geometry_name: String
      let properties: [Properties]   
  }
  
  struct Geometry: Decodable {
      let type: String
      let coordinates: [[Double]]
  }
  
  struct Properties: Decodable {
      let zone_id: String
      let wkt: String
      let contact: String
  }
  </code></pre>
  <pre><code>import SwiftUI
  
  struct ContentView: View {  
      var body: some View {
          Text(&quot;Hello World&quot;)
              .onAppear(perform: readFile)
      }
      
      private func readFile() {
          if let url = URL(string: &quot;https://www.yeltsy.com/wp-content/uploads/2021/08/restrictions.json&quot;),
             let data = try? Data(contentsOf: url) {
              let decoder = JSONDecoder()
              
              if let jsonData = try? decoder.decode(Notam.self, from: data) {
                  print(jsonData.totalFeatures)
              }
          }
      }
  }
  </code></pre>
  <p>The above code works if I comment the geometry and properties constants of Feature struct</p>
  <p><strong>UPDATE 180821</strong>:</p>
  <p>Thanks to the comment of @vadian I found out about the geoJson decoder, therefore I am going to post my code that parse the geoJson and shows the polygon overlays on the map, if anyone needs it.</p>
  <p>Now I am trying to find out a solution on how to show the annotations(check the decodeAnnotations() function below) on the map when the user taps the overlay polygon. Would have been easier if there were pointannotations with a location. But I don't know how to show them if it is a polygon overlay. If anyone has any hint please let me know.</p>
  <pre><code>import SwiftUI
  import MapKit
  import CoreLocation
  
  // All Map Data Goes here...
  
  class MapViewModel: NSObject, ObservableObject, CLLocationManagerDelegate {
      
      @Published var mapView = MKMapView()
      
      @Published var region: MKCoordinateRegion!
      
      // Based on Location it Will set up
      
      // Alert
      @Published var permissionDenied = false
      
      @Published var mapType: MKMapType = .standard
  
      
      func updateMapType() {
          if mapType == .standard {
              mapType = .hybrid
              mapView.mapType = mapType
          }
          else {
              mapType = .standard
              mapView.mapType = mapType
          }
      }
      
      // Focus Location...
      func focusLocation() {
          guard let _ = region else {return}
          
          mapView.setRegion(region, animated: true)
          mapView.setVisibleMapRect(mapView.visibleMapRect, animated: true)
      }
      
      
      func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
          // Checking User Permission for Location Sharing
          
          switch manager.authorizationStatus {
          case .denied:
              // If request denied, alert the user ...
              permissionDenied.toggle()
          case .notDetermined:
              //If not determined, Request permission
              manager.requestWhenInUseAuthorization()
          case .authorizedWhenInUse:
              manager.requestLocation()
              manager.startUpdatingLocation()
          default:
              ()
          }
      }
      
      func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
          print(error.localizedDescription)
      }
      
      func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
          // Getting user Region
          
          guard let location = locations.last else {return}
  
          self.region = MKCoordinateRegion(center: location.coordinate, span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5))
          
          // Updating map
          self.mapView.setRegion(self.region, animated: true)
          
          //Smooth Animation..
          self.mapView.setVisibleMapRect(self.mapView.visibleMapRect, animated: true)
          manager.stopUpdatingLocation()
          
      }
      
      // Decode GeoJSON from the server
          func showRestrictedZones(completion: @escaping ([MKOverlay]) -&gt; ()) {
          guard let url = URL(string: &quot;https://www.yeltsy.com/wp-content/uploads/2021/08/restrictions.json&quot;) else {
              fatalError(&quot;Unable to get geoJSON&quot;) }
          
          downloadData(fromURL: url) { (returnedData) in
              if let data = returnedData {
                  var geoJson = [MKGeoJSONObject]()
                  do {
                      geoJson = try MKGeoJSONDecoder().decode(data)
                  } catch {
                      fatalError(&quot;Unable to decode GeoJSON&quot;)
                  }
                  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)
                              }
                          }
                      }
                  }
                  DispatchQueue.main.async {
                      completion(overlays)
                  }
              }
          }
      }
  
      func decodeAnnotations() {
          guard let url = URL(string: &quot;https://flightplan.romatsa.ro/init/static/zone_restrictionate_uav.json&quot;) else {
              fatalError(&quot;Unable to get geoJSON&quot;) }
          downloadData(fromURL: url) { (returnedData) in
              if let jsonData = returnedData {
                  do {
                      let result = try JSONDecoder().decode(FeatureCollection.self, from: jsonData)
                      for feature in result.features {
                          print(feature.properties.contact)
                      }
                  } catch { print(&quot;Error while parsing: \(error)&quot;) }
              }
          }
      }
  
      func downloadData( fromURL url: URL, completion: @escaping (_ data: Data?) -&gt; ()) {
          URLSession.shared.dataTask(with: url) { (data, response, error) in
              guard
                  let data = data,
                  error == nil,
                  let response = response as? HTTPURLResponse,
                  response.statusCode &gt;= 200 &amp;&amp; response.statusCode &lt; 300 else {
                  print(&quot;Error downloading data.&quot;)
                  completion(nil)
                  return
              }
              completion(data)
          }
          .resume()
      }
  }
  </code></pre>
  <pre><code>import SwiftUI
  import MapKit
  
  struct MapView: UIViewRepresentable {
      
      @EnvironmentObject var mapData: MapViewModel
      
      @State var restrictions: [MKOverlay] = []
      
      func makeCoordinator() -&gt; Coordinator {
          return MapView.Coordinator()
      }
      
      func makeUIView(context: Context) -&gt; MKMapView {
          
          let view = mapData.mapView
          
          view.showsUserLocation = true
          view.delegate = context.coordinator
          
          mapData.showRestrictedZones { (restrictions) in
              self.restrictions = restrictions
              view.addOverlays(self.restrictions)
          }
  
          return view
      }
      
      func updateUIView(_ uiView: MKMapView, context: Context) {
          
      }
      
      class Coordinator: NSObject, MKMapViewDelegate {
          
          func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -&gt; MKOverlayRenderer {
              if let polygon = overlay as? MKPolygon {
                  let renderer = MKPolygonRenderer(polygon: polygon)
                  renderer.fillColor = UIColor.purple.withAlphaComponent(0.2)
                  renderer.strokeColor = .purple.withAlphaComponent(0.7)
                  
                  return renderer
                      
              }
              return MKOverlayRenderer(overlay: overlay)
          }
      }
  }
  </code></pre>
  <pre><code>import SwiftUI
  import CoreLocation
  
  struct Home: View {
      
      @StateObject var mapData = MapViewModel()
      // Location Manager..
      @State var locationManager = CLLocationManager()
      
      var body: some View {
          ZStack{
               MapView()
                  .environmentObject(mapData)
                  .ignoresSafeArea(.all, edges: .all)
              
              VStack {
                  Spacer()
                  
                  VStack{
                      
                      Button(action: mapData.focusLocation, label: {
                          Image(systemName: &quot;location.fill&quot;)
                              .font(.title2)
                              .padding(10)
                              .background(Color.white)
                              
                      })
                      
                      Divider()
                          .frame(width: 20)
                      
                      Button(action: mapData.updateMapType, label: {
                          Image(systemName: mapData.mapType == .standard ? &quot;network&quot; : &quot;map.fill&quot;)
                              .font(.title2)
                              .padding(10)
                              .background(Color.white)
                              
                      })
                  }
                  .background(Color.white)
                  .cornerRadius(10)
                  .frame(maxWidth: .infinity, alignment: .trailing)
                  .shadow(color: Color.black.opacity(0.2), radius: 5, x: 0, y: 5)
                  .padding()
              }
          }
          .onAppear(perform: {
              locationManager.delegate = mapData
              locationManager.requestWhenInUseAuthorization()
          })
          .alert(isPresented: $mapData.permissionDenied, content: {
              Alert(title: Text(&quot;Permission Denied&quot;), message: Text(&quot;Please Enable Permission In App Settings&quot;), dismissButton: .default(Text(&quot;Go To Settings&quot;), action: {
                  // Redirecting user to the settings...
                   UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!)
              }))
          })
      }
  }
  </code></pre>