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 }