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()
}
}