Search code examples
jsonswiftswift-playgroundjsondecoder

JSONDecoder with no output in Swift Playground


I am new to Swift JSON, so I am practicing in Swift Playgrounds. I'm pretty sure that this would be considered decoding a nested JSON key. But like I said, I'm new and I am not familiar with all of the technical terms.

Anyway, I thought that this code was right, but for some reason it won't print. And it's not showing me any error, which is making it harder to fix. But, I must be doing something wrong.

import UIKit

let jsonData :Data = """
{
"id": 1,
"name": "John Smith",
"username": "Johnny",
"email": "[email protected]",
"address": {
    "street": "Some Street",
    "suite": "100",
    "city": "SomeCity",
    "zipcode": "12345",
    }
}

""".data(using: .utf8)!

struct User :Decodable {

    let id :Int
    let name :String
    let userName :String
    let email :String

    let street :String
    let suite :String
    let city :String
    let zipCode :String

    private enum UserKeys :String, CodingKey {
        case id
        case name
        case userName
        case email
        case address
    }

    private enum AddressKeys :String, CodingKey {

        case street
        case suite
        case city
        case zipCode

    }

    init(from decoder :Decoder) throws {

        let userContainer = try decoder.container(keyedBy: UserKeys.self)

        self.id = try userContainer.decode(Int.self, forKey: .id)
        self.name = try userContainer.decode(String.self, forKey: .name)
        self.userName = try userContainer.decode(String.self, forKey: .userName)
        self.email = try userContainer.decode(String.self, forKey: .email)

        let addressContainer = try userContainer.nestedContainer(keyedBy: AddressKeys.self, forKey: .address)

        self.street = try addressContainer.decode(String.self, forKey: .street)
        self.suite = try addressContainer.decode(String.self, forKey: .suite)
        self.city = try addressContainer.decode(String.self, forKey: .city)
        self.zipCode = try addressContainer.decode(String.self, forKey: .zipCode)

    }

}

if let user = try? JSONDecoder().decode(User.self, from: jsonData) {
    print(user.name)
    print(user.city)
}

Solution

  • The userName and zipCode properties are camel-case as they should be following Swift standards. However, as what often happens with JSON data, the keys "username" and "zipcode" are both presented in lowercase. Fortunately, there is an easy fix for this. In your private enums, simply set both of the properties to their lowercase stringValue like this:

     case userName = "username"
     case zipCode = "zipcode"
    

    Technically, I think that your dealing with a nested dictionary of JSON properties. I'm not sure though, maybe some of the experts on this site can elaborate more on that.