Выполнить итерацию по массиву JSON и добавить координаты на карту

#ios #arrays #swift

#iOS #массивы #swift

Вопрос:

Я использую API для получения координат широты и долготы и размещения их на карте с названием места, которому оно соответствует. Я могу указать широтные и длинные координаты одного места, но я не слишком уверен, как добавить их все на карту. Я не могу понять, как это сделать. Я пытался использовать для этого цикл for, но я слишком уверен в том, как я бы это реализовал. Это то, что у меня есть до сих пор:

     func getData() {
        let url = "https://www.givefood.org.uk/api/2/foodbanks/"
        let task = URLSession.shared.dataTask(with: URL(string: url)!, completionHandler: { [self] data, response, error in
            guard let data = data, error == nil else {
                print("Wrong")
                return
            }

            var result: [Info]?

            do {
                result = try JSONDecoder().decode([Info].self, from: data)
            }
            catch {
                print("Failed to convert: (error.localizedDescription)")
            }
            guard let json = result else {
                return
            }
            
            for each in json {
                
                var each = 0
                each  = 1
                
                let comp = json[each].lat_lng?.components(separatedBy: ",")
                
                let latString = comp![each]
                let lonString = comp![each]

                let lat = Double(latString)
                let lon = Double(lonString)
                
                let locationPin: CLLocationCoordinate2D = CLLocationCoordinate2DMake(lat!, lon!)
                
                let location: CLLocationCoordinate2D = CLLocationCoordinate2DMake(51.55573, -0.108312)
                
                let region = MKCoordinateRegion.init(center: location, latitudinalMeters: regionInMetres, longitudinalMeters: regionInMetres)
                
                mapView.setRegion(region, animated: true)

                let myAn1 = MapPin(title: json[each].name!, locationName: json[each].name!, coordinate: locationPin)
                
                mapView.addAnnotations([myAn1])
            }
        })
        task.resume()
    }
 

Ответ №1:

Ваш цикл неправильный, each после for — один Info элемент. Int Индекс each не имеет смысла, и вы устанавливаете его на каждой итерации равным нулю, поэтому вы всегда получаете одну и ту же координату (с индексом 1).

Прежде всего объявить name и lat_lng как необязательный. Все записи содержат оба поля.

 struct Info : Decodable {
    let lat_lng : String
    let name : String
}
 

Во-вторых, из соображений удобства расширьте CLLocationCoordinate2D , чтобы создать координату из строки

 extension CLLocationCoordinate2D {
    init?(string: String) {
        let comp = string.components(separatedBy: ",")
        guard comp.count == 2, let lat = Double(comp[0]), let lon = Double(comp[1]) else { return nil }
        self.init(latitude: lat, longitude: lon )
    }
}
 

В-третьих, поместите весь хороший код в область do видимости вместо того, чтобы иметь дело с опциями, и установите регион один раз перед циклом

 func getData() {
    let url = "https://www.givefood.org.uk/api/2/foodbanks/"
    let task = URLSession.shared.dataTask(with: URL(string: url)!, completionHandler: { [self] data, response, error in
        if let error = error { print(error); return }
        
        do {
            let result = try JSONDecoder().decode([Info].self, from: data!)
            let location = CLLocationCoordinate2D(latitude: 51.55573, longitude: -0.108312)
            let region = MKCoordinateRegion.init(center: location, latitudinalMeters: regionInMetres, longitudinalMeters: regionInMetres)
            mapView.setRegion(region, animated: true)
            var pins = [MapPin]()
            for info in result {
                if let coordinate = CLLocationCoordinate2D(string: info.lat_lng) {                      
                    pins.append(MapPin(title: info.name, locationName: info.name, coordinate: coordinate))
                    
                }
            } 
            DispatchQueue.main.async {
                self.mapView.addAnnotations(pins)
            }
        }
        catch {
            print("Failed to convert: (error)")
        }
    })
    task.resume()
}