Я пытался декодировать 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 в целом будут полезны.
Есть две проблемы:
Ошибка возникает, поскольку объект ключа 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)
}
}
Большое спасибо за ваш вклад, Вадиан. Мне удалось собрать данные. Последний вопрос: есть ли способ фильтровать данные по определенным ключам для заполнения текстового поля? На данный момент он извлекает все в структуре записей, однако я хотел бы извлечь только два поля для определенного текстового поля.
Да, есть filter
API. Например, прочитайте sarunw.com/posts/swift-array-filter
Передайте свой JSON в fasttype.io