Learn Courses My Dashboard

How to write JSON as Swift Struct?

Hi,

I have a JSON looking like this, but how can I write this as a Swift Structure?
Would really appreciate the help

First it’ll be an array of objects. So to give a name of the entire thing object itself let’s call it Obj. Also it’s not a single object, but this is composed of multiple different objects.

Inside of Obj is an object, let’s call it OtherObj. This contains action, and trigger.
Action contains a type, and then trigger contains url-filter.

struct Obj {
   let otherObjs: [OtherObj]
}

struct OtherObj {
   let action: Action
   let trigger: Trigger
}

struct Action {
   let type: Type
}

struct Type: {
   let stringType: String // not sure what to call this
}

struct Trigger {
   let urlFilter: String // not sure if this will always be a string
}

So pretty much anything that has { } curly braces around it, that is an object with properties inside it

Thanks for the quick answer, I think I get what you are saying.
But would something like this also be possible

I believe so, but I think it’ll start to get weird with the decoding.

Instead of just having Object.decode

You’d have to manually decode out each part of the dictionary

No, that wouldn’t work. action and trigger are already accounted for as keys in the outer object so you can’t then use also them as keys in the inner object.

You would either need to do this:

struct Obj: Codable {
    let action: [String: String]
    let trigger: [String: String]
}

or this:

typealias Obj = [String:[String:String]]

in order for this to work using the JSON you provided:

let json = """
[
    {
        "action": {
            "type": "block"
        },
        "trigger": {
            "url-filter": "apple.com"
        }
    }
]
""".data(using: .utf8)!

let decoder = JSONDecoder()
do {
    let obj = try decoder.decode([Obj].self, from: json)
    print(obj)
}
catch {
    print(error)
}

//1st way returns an array containing struct with
//  action property: ["type": "block"] and trigger property: ["url-filter": "apple.com"]
//2nd one returns: [["action": ["type": "block"], "trigger": ["url-filter": "apple.com"]]]

(PS: Post your code as text rather than screenshots. That makes it far easier for people to help you because they can just copy/paste rather than having to retype everything in order to test it out.]

1 Like

Thanks for the answer, I’m getting a bit confused as what to do.
Let me explain my goal, I currently have this code where I basically write to a JSON file, which works fine. My goal is to create the Friends structure in a way that I end up with the JSON file I linked before.

When it outputs this ["action": ["type": "block"] are the square brackets equivalent to these brackets {} in the JSON file?

 func saveFriends(friends: [Friends]) {
            let documentsDirectory = FileManager().containerURL(forSecurityApplicationGroupIdentifier: "SomeBundleID")
        
           let archiveURL = documentsDirectory?.appendingPathComponent("nickFriends.json")
            let encoder = JSONEncoder()
        
            if let dataToSave = try? encoder.encode(friends) {
                do {
                    try dataToSave.write(to: archiveURL!)
                    print("Sucess")
                } catch {
                    print(error)
                    return
                }
            }
        }

struct Friends: Codable {
     var action: [String: String]
     var trigger: [String: String]

}

Essentially, yes. The JSON object indicated by the curly brackets { } corresponds to the Swift Dictionary object indicated by square brackets [ ].

JSON arrays indicated by square brackets [ ] likewise correspond to Swift Arrays also indicated by square brackets [ ].

So your initial JSON:

[
    {
        "action": {
            "type": "block"
        },
        "trigger": {
            "url-filter": "apple.com"
        }
    }
]

can be decoded into a Swift array of dictionaries:

[
    [
        "action": [
            "type": "block"
        ],
        "trigger": [
            "url-filter": "apple.com"
        ]
    ]
]

which, when written more compactly, becomes:

[["action":["type":"block"],"trigger":["url-filter":"apple.com"]]]

Either of the three approaches shown to you in this thread will work for that. It just depends how you would prefer to work with your Friend struct.

(And you should call it Friend instead of Friends since it’s a single object. Then, in your saveFriends function, your parameter would read like friends: [Friend], meaning the friends parameter is an array of Friend objects, not an array of Friends objects. Reads much better that way and is easier to understand. After all, code is written for humans to read and understand.)

Okay Great. Thanks for the help, it was really useful.

If you have the time I would really appreciate it, if you could take a look at this post I made last week