UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

A doubt on declaration

Forums > SwiftUI

Hi, here we go again with JSON Decode and Struct.

This time around the problem is in the JSON but I cannot modify it, I need to find a way around it.

{
  "id": 1,
  "user": {
    "id": 1,
    "user_details": {
      "address": "some text"
    }
  }
},
{
  "id": 2,
  "user": {
    "id": 300,
    "user_details": false
  }
}

Now, I'm sure you got it already.

What do I do with that "user_details"? It's either something or false.

If I go


struct Main: Codable, Identifiable {
  let id: Int
  let user: User
}

struct User: Codable, Identifiable {
  let id: Int
  let user_details: UserDetails?
}

struct UserDetails: Codable, Identifiable {
  let id: Int
  let address: String
}

that won't work, because of course in the second JSON node the value of user_details is FALSE not nil: false

I don't know how to solve it... give me some rope, I am a super newbie... :/

ps: is an example I've recreated to semplify the case, of course a JSON like this would be stupid.

3      

Hi, have you tried with guard let and putting default data in case of else? Hope I understood the problem

3      

To be more clear, use an optional for maybe false data

3      

I don't think I follow...

On top of that even if you use an optional is still boolean when false, it's not nil. The Optional fails.

I should I declare the constant user in my User struct?

3      

Thats badly designed JSON so if you can get that changed at the server side you should. They can leave out the user_details and let it not exist, rather than set it to false which makes the type ambigous. If it were nil the optional would work.

If they cant or won't fix it then you will have to dig in into the guts of doing your own handling of decoding the JSON.

I think Paul has a post on that.

In the meantime here is something I used to handle a case where I could get a double or a string in a badly formatted weather API.

enum StringOrDouble: Decodable {

    case string(String)
    case double(Double)

    init(from decoder: Decoder) throws {
        if let double = try? decoder.singleValueContainer().decode(Double.self) {
            self = .double(double)
            return
        }
        if let string = try? decoder.singleValueContainer().decode(String.self) {
            self = .string(string)
            return
        }
        throw Error.couldNotFindStringOrDouble
    }
    enum Error: Swift.Error {
        case couldNotFindStringOrDouble
    }
}

So this is a newType which conforms to codable. On initialization, from the decoder, which happens when the parent class is being decoded it trys to catch whether this is a double or a string and sets the values of it self approriately ( as an enum).

Its a bit more difficult for you but you could do something similar.

3      

I tried this, seemed to work

struct User: Decodable, Identifiable {
  let id: Int
  var userDetails: UserDetailsOrBool? = nil

    enum CodingKeys: String , CodingKey  {
          case id
          case userDetails = "user_details"
      }

    init(from decoder: Decoder) throws {
          let container = try decoder.container(keyedBy: CodingKeys.self)
        id  = try container.decode(Int.self, forKey: .id)
        userDetails  = try container.decode(UserDetailsOrBool.self, forKey: .userDetails)

      }

}

struct UserDetails: Decodable, Identifiable {
  let id: Int?
  let address: String?
}

enum UserDetailsOrBool: Decodable {

    case userDetails(UserDetails)
    case exists(Bool)

    init(from decoder: Decoder) throws {
        if let userDetails = try? decoder.singleValueContainer().decode(UserDetails.self) {
            self = .userDetails(userDetails)
            return
        }
        if let exists = try? decoder.singleValueContainer().decode(Bool.self) {
            self = .exists(exists)
            return
        }
        throw Error.couldNotFindUserDetailsOrBool
    }

    enum Error: Swift.Error {
        case couldNotFindUserDetailsOrBool
    }
}

3      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.