PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Saturday, July 23, 2022

[FIXED] How to read and display a dictionary from JSON?

 July 23, 2022     json, swift, swiftui     No comments   

Issue

I am working on an app that fetches the data from JSON and displays it. However, I am stuck with an error saying Instance method 'appendInterpolation(_:formatter:)' requires that '[String : Int]' inherit from 'NSObject'

Here is my data structure:

struct Data: Codable {
    var message: String
    var data: Objects
}

struct Objects: Codable {
    var date: String
    var day: Int
    var resource: String
    var stats, increase: [String: Int]
}

Function to fetch the data:

func getData() {
    let urlString = "https://russianwarship.rip/api/v1/statistics/latest"
    let url = URL(string: urlString)
    
    URLSession.shared.dataTask(with: url!) { data, _, error in
        if let data = data {
            do {
                let decoder = JSONDecoder()
                let decodedData = try decoder.decode(Data.self, from: data)
                self.data = decodedData
            } catch {
                print("Hey there's an error: \(error.localizedDescription)")
            }
        }
    }.resume()
}

And a ContentView with the @State property to pass the placeholder data:

struct ContentView: View {

@State var data = Data(message: "", data: Objects(date: "123", day: 123, resource: "", stats: ["123" : 1], increase: ["123" : 1]))


var body: some View {
    VStack {
        Button("refresh") { getData() }
        Text("\(data.data.date)")
        
        Text("\(data.data.day)")
        
        Text(data.message) 
        
        Text("\(data.data.stats)") //error is here
        

Here is an example of JSON response

JSON Str

I wonder if the problem is in data structure, because both

Text("\(data.data.date)")            
Text("\(data.data.day)")

are working just fine. If there are any workarounds with this issue – please, I would highly appreciate your help!:)


Solution

stats is [String: Int], and so when you want to use it, you need to supply the key to get the value Int, the result is an optional that you must unwrap or supply a default value in Text

So use this:

 Text("\(data.data.stats["123"] ?? 0)")

And as mentioned in the comments, do not use Data for your struct name.

EDIT-1: there are two ways you can make the struct fields camelCase; one is using the CodingKeys as shown in ItemModel, or at the decoding stage, as shown in the getData() function. Note, I've also updated your models to make them easier to use.

struct DataModel: Codable {
    var message: String
    var data: ObjectModel
}

struct ObjectModel: Codable {
    var date: String
    var day: Int
    var resource: String
    var stats: ItemModel
    var increase: ItemModel
}

struct ItemModel: Codable {
    var personnelUnits: Int
    var tanks: Int
    var armouredFightingVehicles: Int
    // ...
    
    // manual CodingKeys
    //    enum CodingKeys: String, CodingKey {
    //        case tanks
    //        case personnelUnits = "personnel_units"
    //        case armouredFightingVehicles = "armoured_fighting_vehicles"
    //    }
}


struct ContentView: View {
    
    @State var dataModel = DataModel(message: "", data: ObjectModel(date: "123", day: 123, resource: "", stats: ItemModel(personnelUnits: 123, tanks: 456, armouredFightingVehicles: 789), increase: ItemModel(personnelUnits: 3, tanks: 4, armouredFightingVehicles: 5)))
    
    var body: some View {
        VStack {
            Button("get data from Server") { getData() }
            Text("\(dataModel.data.date)")
            Text("\(dataModel.data.day)")
            Text(dataModel.message)
            Text("\(dataModel.data.stats.armouredFightingVehicles)") // <-- here
        }
    }
    
func getData() {
    let urlString = "https://russianwarship.rip/api/v1/statistics/latest"
    if let url = URL(string: urlString) {
        URLSession.shared.dataTask(with: url) { data, _, error in
            if let data = data {
                do {
                    let decoder = JSONDecoder()
                    decoder.keyDecodingStrategy = .convertFromSnakeCase  // <-- here
                    dataModel = try decoder.decode(DataModel.self, from: data)
                } catch {
                    print("--> error: \(error)")
                }
            }
        }.resume()
    }
}
    
}


Answered By - workingdog support Ukraine
Answer Checked By - Pedro (PHPFixing Volunteer)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing