Home > Software design >  Swift 5 : Create JSON with Codable / Struct from my variables
Swift 5 : Create JSON with Codable / Struct from my variables

Time:04-08

I would like to create a Codable structure to save data from a user profile Let's say the ios user filled a form with his name, last name,adress, put his picture (UIImage)) and that user have an unique ID . My JSON would be like

{"Unique_ID" :"1234556778", 
    {"Name":"John",
     "Last Name" : "Doe",
     "adress" :
        {"street": "21 jump street",
         "country" : "USA"}
     } 
}

I tried to create the Codable but I think it isn't optimal , could you kindly give me some hint to optimize it or tell me if I'm wrong doing it like this ?

        struct User_Profile: Codable {
        let Unique_ID : String
        let Data_Of_User : User_Profile_Data
         }

  struct User_Profile_Data: Codable {
        let name : String
        let last_name: String
        let adress : User_Adress_Data
       }

  struct User_Adress_Data: Codable {
        let street : String
        let country: String
       }



override func viewDidLoad() {
        super.viewDidLoad()
        
        let usernametest = "John"
     
        let b = User_Adress_Data(street: "21 jump street", country: "USA")
        let c = User_Profile_Data(name: usernametest, last_name: "Doe", adress: b)
        let d = User_Profile(Unique_ID: "123456", Data_Of_User: c)
        }

After that, I would like to cache it, with Haneke swift(https://github.com/Haneke/HanekeSwift), or Datacache (https://github.com/huynguyencong/DataCache) How can I cache my Codables? (for eg, I didn't view any 'set cache for json' with Haneke)

And finally, I would like to use it after fetched with SwiftyJSON : (https://github.com/SwiftyJSON/SwiftyJSON), and I don't know if my Codables are enought readable for it.

Thanks for your idea/comment !

CodePudding user response:

As you have full controll over your structure and there is no collection involved i would recommend to put everything in one struct instead of scattering it over many different:

struct UserProfile: Codable{
    var id: String
    var name: String
    var lastname: String
    var street: String
    var country: String
}

Regarding caching. As you can mark this struct Codable it can be easily stored in Userdefaults as Data. This extension on Userdefaults should allow you to access UserProfile in a typesafe manner.

extension UserDefaults{
    var userProfile: UserProfile?{
        get{
            guard let data = data(forKey: "userProfile") else{
                return nil
            }
            
            return try? JSONDecoder().decode(UserProfile.self, from: data)
        }
        set{
            set(try? JSONEncoder().encode(newValue), forKey: "userProfile")
        }
    }
}

Usage example:

//Write
UserDefaults.standard.userProfile = UserProfile(id: UUID().uuidString, name: "First", lastname: "Last", street: "nowhere", country: "atlantis")
//Read
let profile = UserDefaults.standard.userProfile

Edit: Editing example:

As this is a struct it gets copied every time something changes. So read the value in a var. Modify it and save it to the defaultStore.

var profile = UserDefaults.standard.userProfile
profile?.country = "newCountry"
UserDefaults.standard.userProfile = profile

CodePudding user response:

The example you've provided isn't valid JSON. It looks like some sort of hybrid of a dictionary and an array.

So let's make a few tweaks:

{
  "Unique_ID": "1234556778",
  "Data_of_User": {
    "First_Name": "John",
    "Last_Name": "Doe",
    "Address": {
      "Street": "21 jump street",
      "Country": "USA"
    }
  }
}

Then you can create structs which look like:

struct UserProfile: Codable {
    let uniqueID: String
    let userData: UserData
    
    enum CodingKeys: String, CodingKey {
        case uniqueID = "Unique_ID"
        case userData = "Data_of_User"
    }
}

struct UserData: Codable {
    let firstName: String
    let lastName: String
    let address: Address
    
    enum CodingKeys: String, CodingKey {
        case firstName = "First_Name"
        case lastName = "Last_Name"
        case address = "Address"
    }
}

struct Address: Codable {
    let street: String
    let country: String
    
    enum CodingKeys: String, CodingKey {
        case street = "Street"
        case country = "Country"
    }
}

CodePudding user response:

Codable requires the property names in your struct to match the json counterparts. In your User_Profile_Data struct you have name while the json contains "Name" and you have last_name where the json contains "Last Name".

One way to get around this is to add a CodingKeys enum to your struct that tells it how to map the properties. So in your User_Profile_Data struct I would add:

enum CodingKeys: String, CodingKey { case name = "Name" case last_name = "Last Name" case adress }

  • Related