Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

macOS - Getting JSON data from Raw Github + Parsing

Tags:

json

arrays

swift

I am trying to get json from a githubusercontent (URL: https://raw.githubusercontent.com/nacrt/SkyblockClient-REPO/main/files/mods.json) into a Swift file then converting it into something that I can manipulate, for example, using enabled (below) to have a checkbox checked/unchecked. The JSON in question is actually an array of JSONs, and this is the main problem. I'm not sure if the code below will work, because I haven't imported the JSON.

So far, I've found this:

struct ModsJSON: Decodable {
    let id: String
    let display: String
    let description: String
    let url: String
    let config: Bool?
    let enabled: Bool
    let hidden: Bool
    let icon: String
    let categories: Array<String>
    let actions: Array<OptionAction>?
    let warning: ActionWarning?
}

let jsonData = JSON.data(using: .utf8)! //JSON being the imported json
let mods_json: [ModsJSON] = try! JSONDecoder().decode([ModsJSON].self, from: jsonData)

I am a beginner in swift, and I realize that this should be easy, but I can't find a practical answer anywhere.

macOS Big Sur - Latest Swift and Xcode versions.

like image 783
stefthedoggo4 Avatar asked Feb 25 '26 09:02

stefthedoggo4


2 Answers

It's not that easy for a beginner, you have to load the data asynchronously with URLSession.

Some of the keys in the JSON dictionaries are missing, therefore you have to declare more struct members as optional.

The types for the keys actions and warning are missing, I commented them out, the code works without them, too

struct Mod: Decodable {
    let id: String
    let display: String
    let description: String
    let url: String?
    let config: Bool?
    let enabled: Bool?
    let hidden: Bool?
    let icon: String?
    let categories: [String]?
    // let actions: Array<OptionAction>?
    // let warning: ActionWarning?
}

let url = URL(string: "https://raw.githubusercontent.com/nacrt/SkyblockClient-REPO/main/files/mods.json")!

let task = URLSession.shared.dataTask(with: url) { (data, _, error) in
    if let error = error { print(error); return }
    do {
        let result = try JSONDecoder().decode([Mod].self, from: data!)
        print(result)
    } catch { print(error) }
}
task.resume()

There are some bad practices in your code:

  • Instead of try! use always a do - catch block if an error could occur.
  • Variable names in Swift are lowerCamelCase rather than snake_case.
  • Don't annotate types the compiler can infer.
  • Structs used in an array should be named in singular form (Mod) and the JSON suffix is pointless.
like image 78
vadian Avatar answered Feb 28 '26 00:02

vadian


Vadian is correct. Whatever is not present in any of the elements of the array must be marked Optional:

struct ModsJSON: Decodable {
    let id: String
    let display: String
    let description: String
    let url: String?
    let config: Bool?
    let enabled: Bool?
    let hidden: Bool?
    let icon: String?
    let categories: Array<String>?
    // let actions: Array<OptionAction>?
    //let warning: ActionWarning?
}

Your code will then successfully parse the JSON. You can then, as you say, learn all the enabled values by saying eg.

let enableds = mods_json.map {$0.enabled}

But some of the elements lack the enabled so you would have to decide how to deal with that. The results appear as

[Optional(true), Optional(true), nil, Optional(true), Optional(true), Optional(true), Optional(true), nil, nil, nil, nil, nil, nil, nil, Optional(false), nil, Optional(false), Optional(false), nil, Optional(false), Optional(false), Optional(false), nil, nil]

How to reflect this data into your interface is a totally different problem!

like image 22
matt Avatar answered Feb 28 '26 00:02

matt