I have this JSON-File coming from a MySQL-Database via PHP:
[
{
"id":1,
"partner":{
"id":1,
"name":"Migros Bank",
"image":"migrosbank"
},
"name":"Testkonto 1",
"type":"bank",
"iban":"CH12 1234 1234 1234 1234 1",
"datapoints":[
{
"id":1,
"depot_id":1,
"date":"2021-12-28",
"amount":5811.490234375
},
{
"id":2,
"depot_id":1,
"date":"2021-12-29",
"amount":7736.89013671875
}
]
},
{
"id":2,
"partner":{
"id":1,
"name":"Migros Bank",
"image":"migrosbank"
},
"name":"Testkonto 2",
"type":"bank",
"iban":"CH12 1234 1234 1234 1234 2",
"datapoints":[
{
"id":3,
"depot_id":2,
"date":"2021-12-28",
"amount":500
},
{
"id":4,
"depot_id":2,
"date":"2021-12-29",
"amount":1500
}
]
}
]
In SwiftUI I try to decode it to a custom struct called Depot which consists of one instance of the custom struct Partner and an array of Instances of the custom struct Depotstand:
import Foundation
import SwiftUI
struct Partner: Hashable, Codable, Identifiable {
var id: Int
var name: String
var image: String
var imageName: Image {
Image(image)
}
}
struct Depotstand: Hashable, Codable, Identifiable {
var id: Int
var depot_id: Int
var date: Date
var amount: Double
}
struct Depot: Hashable, Codable, Identifiable {
var id: Int
var partner: Partner
var name: String
var type: String
var iban: String
var datapoints: [Depotstand]
}
I've added a data-model, to get the JSON-data from my webserver - this part works fine - and then I try to decode the data to the custom struct Depot, which fails (it works, if I simplify the JSON/struct to only the simple Depot struct without depending on Partner and Depotstand instances):
import Foundation
final class ModelDataDepot: ObservableObject {
@Published var depots = [Depot]()
init(){
let url = URL(string: "https://api.webcoders.ch/index.php")!
URLSession.shared.dataTask(with: url) { (data, response, error) in
do {
if let data = data {
let decodedData = try JSONDecoder().decode([Depot].self, from: data)
DispatchQueue.main.async {
self.depots = decodedData
}
} else {
print("No Data!")
}
} catch {
print("JSON-Error: \(error)")
}
}.resume()
}
}
Here is the error I get which contains mainly data-type errors, but I have no idea to get around this:
JSON-Error: typeMismatch(Swift.Double, Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "datapoints", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "date", intValue: nil)], debugDescription: "Expected to decode Double but found a string/data instead.", underlyingError: nil))
I've already tried some different data-casting, even using Numberformatters etc. but I can't get it to work...
Thanks for helping me out!
P.s: I am an absolute beginner to SwiftUI and mobile development in general... My coding background is mainly PHP, PowerShell and such, so please be patient with me. :-)
The most important part of the error message is this:
CodingKeys(stringValue: "date", intValue: nil)], debugDescription: "Expected to decode Double but found a string/data instead."
In your JSON text, the value for "date" is string, but in your struct, you are trying to pass the value to Date not String.
What you may need is not a Numberformatter, but setting dateDecodingStrategy:
final class ModelDataDepot: ObservableObject {
@Published var depots = [Depot]()
private let dateFormatter: DateFormatter = {
let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd"
df.locale = Locale(identifier: "en_US_POSIX")
return df
}()
init() {
let url = URL(string: "https://api.webcoders.ch/index.php")!
URLSession.shared.dataTask(with: url) { (data, response, error) in
if let error = error {
print(error)
return
}
guard let data = data else {
print("No Data!")
return
}
do {
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(self.dateFormatter)
let decodedData = try decoder.decode([Depot].self, from: data)
DispatchQueue.main.async {
self.depots = decodedData
}
} catch {
print("JSON-Error: \(error)")
}
}.resume()
}
}