Home > Back-end >  Decoding JSON coming from MySQL via PHP to a complex Struct in SwiftUI
Decoding JSON coming from MySQL via PHP to a complex Struct in SwiftUI

Time:01-02

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... I also checked out this article about casting JSON-data into complex swift struct, but I was not able to resolve my issues.

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. :-)

CodePudding user response:

you could try this with var date: Date :

final class ModelDataDepot: ObservableObject {
    @Published var depots = [Depot]()

let dataDateFormat: DateFormatter = {
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd"
    return formatter
}()
    
    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 decoder = JSONDecoder()
                    decoder.dateDecodingStrategy = .formatted(self.dataDateFormat)  //<-- here
                    let decodedData = try decoder.decode([Depot].self, from: data)
                    DispatchQueue.main.async {
                        print("\n-----> decodedData: \(decodedData) \n")
                        self.depots = decodedData
                    }
                } else {
                    print("No Data!")
                }
            } catch {
                print("JSON-Error: \(error)")
            }
        }.resume()
    }
}

struct Depotstand: Hashable, Codable, Identifiable {
    var id: Int
    var depot_id: Int
    var date: Date  
    var amount: Double
}
  • Related