thoughtbot/Argo

Having Additional properties that are not on the JSON Object

plspalding opened this issue · 5 comments

I would like to add an additional property onto my objects. However this property does not exist on the json object. If I do a let property then I can set the object and everything compiles fine. However I would like to be able to change this particular property on the object later on so I changed it to a var and I get an error message.

Error Messages

Cannot convert value of type '(String, String, Bool, SortingValues) -> Restaurant' to expected argument type '() -> () -> (_) -> Restaurant'

Sample JSON

{
	"restaurants": [{
		"name": "Tanoshii Sushi",
		"status": "open",
		"sortingValues": {
			"bestMatch": 0.0,
			"newest": 96.0,
			"ratingAverage": 4.5,
			"distance": 1190,
			"popularity": 17.0,
			"averageProductPrice": 1536,
			"deliveryCosts": 200,
			"minCost": 1000
		}
	}, {
		"name": "Tandoori Express",
		"status": "closed",
		"sortingValues": {
			"bestMatch": 1.0,
			"newest": 266.0,
			"ratingAverage": 4.5,
			"distance": 2308,
			"popularity": 123.0,
			"averageProductPrice": 1146,
			"deliveryCosts": 150,
			"minCost": 1300
		}
	}]
}

Models

struct Restaurant: Equatable {
    
    public static func ==(lhs: Restaurant, rhs: Restaurant) -> Bool {
        return lhs.name == rhs.name
    }

    let name: String
    let status: String
    var isFavorite: Bool = false // This is the property I would like to add but doesn't exist in the json.
    let sortingValues: SortingValues
}

extension Restaurant: Decodable {
    static func decode(_ json: JSON) -> Decoded<Restaurant> {
        return curry(Restaurant.init)
            <^> json <| "name"
            <*> json <| "status"
            <*> json <| "sortingValues"
    }
}
}

Argo Version

Argo (4.1.2)

Dependency Manager

Cocoapods

Thanks.

I'm pretty sure this is because doing that changes the default initializer that Swift generates for your model. You should try creating your own init so you can cater it to your exact needs in cases like this.

Also, this issue probably has more to do with the default value. If you remove the default value, then you'll need to specify that property in the decode function if it's a let or a var. With a default value, a let property does not generate that value in the init since you set the constant. In the case of a var, the generated init will contain that property which is why you're getting the error in your decode function.

Hi Tony, thanks for the response. I have tried adding my own custom init method inside my Restaurant struct but am still getting the same error. I have also tried having a var without a default value and with a default value. All seem to produce the same error. Please see code below:

struct Restaurant: Equatable {
    
    public static func ==(lhs: Restaurant, rhs: Restaurant) -> Bool {
        return lhs.name == rhs.name
    }

    let name: String
    let status: String
    var isFavorite: Bool
    //  var isFavorite: Bool = false
    let sortingValues: SortingValues
    
    var currentStatus: Double {
        get {
            
            switch status {
                case "open":
                return 2
                case "order ahead":
                return 1
                default:
                return 0
                
            }
        }
    }
    
    init(name: String, status: String, isFavorite: Bool = false, sortingValues: SortingValues) {
        self.name = name
        self.status = status
        self.isFavorite = isFavorite
        self.sortingValues = sortingValues
    }
}

Is there something I need to do in the decode method?

Many thanks.

Did you update your decode function to have 4 properties? If your init takes 4 properties you'll need to make sure the decode function lines up too. It looks like the decode function you have above is missing the isFavorite key. If that isn't being parsed in the JSON, you'll still need to add it to your model. You can add a default like this <*> pure(false).

👍
Yes, I was missing <*> pure(false) . Everything now works as expected.

Many thanks :-)

Good to hear!