Как декодировать вызов JSON API (php), а затем отображать его в виде текста в ScrollView — SWIFTUI

Я пытался декодировать JSON из имеющегося у меня PHP, а затем отображать результаты в виде текста. Я получаю одну из двух ошибок во всем, что я пробовал. Первой проблемой будет: «Ожидали декодирования массива, но вместо этого нашли словарь». Я изменил кое-что в структуре, которая у меня была для этого, и решил эту проблему. Однако затем у меня возникла проблема с отсутствием данных о звонке.

Вот соответствующая часть кода, которая у меня есть для этого. В настоящее время я использую второе представление для тестирования и первое представление в качестве элемента управления.

struct CallData: Decodable, Identifiable{
    
    private enum CodingKeys: String, CodingKey { case records}
    
    let id = UUID()
    let gdata: [Record]
    
    init(from decoder: Decoder) throws {
        
        let container = try decoder.container(keyedBy: CodingKeys.self)
        let records = try container.decode([String:[String]].self, forKey: .records)
        gdata = records.map(Record.init).sorted{$0.iD < $1.iD}
    }
}

struct Record {
    
    let iD: String
    let data: [String]
}

class ContentModel: ObservableObject {
    
    @Published var records = [Record]()
    
    init() {
        getData()
    }
    
    func getData(){
        


        let url = URL(string: "https://not.the.real.php?route=Green")
        
        if let url = url {

            var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 10)
            request.httpMethod = "GET"
             


            URLSession.shared.dataTask(with: request){ (data, response, error) in
                if error == nil {
                    
                    do {
                        let decoder = JSONDecoder()
                        let result = try decoder.decode(CallData.self, from: data!)
                        print(result)
                        
                        DispatchQueue.main.async {
                            self.records = result.gdata
                        }
                    } catch {
                        print(error)
                    }
                }
            }.resume()
            
        }
    }
    
}

struct FirstTabView: View{
    
    @Namespace var mapScopeRed
    
    var body: some View {
        
        VStack{
            
            ScrollView{
                
                
                Text("Red \nred")
            }
            
            Map(scope: mapScopeRed){
                
                
                Marker("Here", coordinate: .You)
                
               
                
                
            }.mapStyle(.hybrid(elevation: .realistic))
            
            MapUserLocationButton(scope: mapScopeRed).tint(.red)
            
            
        }.mapScope(mapScopeRed)
        
        
    }
    
}

struct SecondTabView: View{
    
 
    @Namespace var mapScope
    
    @State var gmodel = [CallData]()
    
    
    var body: some View {
        
        
        VStack{
            
            List(gmodel) { route in
                ScrollView{
                    
                    let ginfo =  "\(route.gdata)"
                    Text(ginfo)
                }
            }
            Map(scope: mapScope){
                
                
                Marker("Here", coordinate: .Youtoo)
                
                
                
            }.mapStyle(.hybrid(elevation: .realistic))
            
            MapUserLocationButton(scope: mapScope).tint(.red)
            
            
        }.mapScope(mapScope)
        
    }
}

Я также включу то, что структура JSON получается из веб-результатов файла php.

{"records":[{"ID":"354","route":"Green","stop_name":"StopOne","lat":"-11.11","lng":"11.11","stop_order":"1","stop_time":"5","NewOrder":"1"},{"ID":"355","route":"Green","stop_name":"StopTwo","lat":"-11.11","lng":"11.11","stop_order":"2","stop_time":"60","NewOrder":"2"},{"ID":"356","route":"Green","stop_name":"StopThree","lat":"-11.11","lng":"11.11","stop_order":"3","stop_time":"30","NewOrder":"3"},{"ID":"357","route":"Green","stop_name":"StopFour","lat":"-11.11","lng":"11.11","stop_order":"4","stop_time":"42","NewOrder":"4"},{"ID":"358","route":"Green","stop_name":"StopFive","lat":"-11.11","lng":"11.11","stop_order":"5","stop_time":"54","NewOrder":"5"},{"ID":"359","route":"Green","stop_name":"StopSix","lat":"-11.11","lng":"11.11","stop_order":"6","stop_time":"95","NewOrder":"6"}]}

Как уже говорилось ранее, я попробовал множество разных вещей, которые нашел в Интернете, но на самом деле ничего не привело к получению данных Observable. Я хотел бы иметь возможность отображать каждое имя_остановки и соответствующее время_остановки в режиме прокрутки. Я предполагаю, что моя проблема связана с тем, как у меня есть структуры CallData и/или Record, которые я настроил (или, возможно, мой класс ContentModel). Я совершенно новичок в Swift, поэтому любые советы по этому поводу или Swift в целом будут полезны.

Передайте свой JSON в fasttype.io

Larme 09.07.2024 18:00
Как сделать HTTP-запрос в Javascript?
Как сделать HTTP-запрос в Javascript?
В JavaScript вы можете сделать HTTP-запрос, используя объект XMLHttpRequest или более новый API fetch. Вот пример для обоих методов:
0
1
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Есть две проблемы:

Ошибка возникает, поскольку объект ключа records представляет собой массив словарей [String:[String:String]], а не словарь со значениями массива [String:[String]].

Другая проблема заключается в том, что в словарях iD нет ключа I (строчной D и прописной records).

Простое решение — принять Decodable в Record

struct Record : Decodable {
    let ID: String
    let route: String
    let stop_name, lat, lng : String
}

и раскодируем [Record].self

struct CallData: Decodable, Identifiable{
    
    private enum CodingKeys: String, CodingKey { case records}
    
    let id = UUID()
    let gdata: [Record]
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        gdata = try container.decode([Record].self, forKey: .records)
    }
}

Большое спасибо за ваш вклад, Вадиан. Мне удалось собрать данные. Последний вопрос: есть ли способ фильтровать данные по определенным ключам для заполнения текстового поля? На данный момент он извлекает все в структуре записей, однако я хотел бы извлечь только два поля для определенного текстового поля.

HKelz 10.07.2024 18:12

Да, есть filter API. Например, прочитайте sarunw.com/posts/swift-array-filter

vadian 10.07.2024 18:45

Другие вопросы по теме