I have the object below:
class Food {
var cal: Int
var displayName: String
var imgUrl: String
var dishType: DishType
init(cal: Int, displayName: String, imgUrl: String, dishType: DishType) {
self.cal = cal
self.displayName = displayName
self.imgUrl = imgUrl
self.dishType = dishtype
}
}
enum DishType {
case starter
case main
case desert
}
And this is a part of my Alamofire request:
if let cal = foodJson["cal"].int,
let displayName = foodJson["display_name"].string,
let dishType = foodJson["type"].string,
let imgUrl = foodJson["imgUrl"].string {
let food = Food(cal: cal, displayName: displayName, imgUrl: imgUrl, dishType: ??)
foods.append(food)
How can I convert the Json String "dishType" into a "DishType" type I created with the enum in order to correctly fill my instance of Food?
You might want to specify an associated value for your enum:
enum DishType: String {
case starter = "starter"
case main = "main"
case desert = "desert"
}
Or, more simply:
enum DishType: String {
case starter
case main
case desert
}
Then you can do:
dishType = DishType(rawValue: string)
e.g.
if let dishTypeString = foodJson["type"].string,
let dishType = DishType(rawValue: dishTypeString) {
...
}
Personally, if doing Swift 4, I'd retire SwiftyJSON
and use the native JSONDecoder
and declare your types to be Codable
. (Note, we still need to define the DishType
to have associated values, like above.)
For example, let's imagine your response was something like:
{
"foods": [{
"cal": 800,
"display_name": "Beef",
"imgUrl": "http://example.com/wheres_the_beef.jpg",
"dishType": "main"
},
{
"cal": 2000,
"display_name": "Chocolate cake",
"imgUrl": "http://example.com/yummy.jpg",
"dishType": "desert"
}
]
}
You could then define your types like so:
struct Food: Codable {
let cal: Int
let displayName: String
let imgUrl: String
let dishType: DishType
}
enum DishType: String, Codable {
case starter
case main
case desert
}
And then you can parse the response like so:
struct FoodsResponse: Codable {
let foods: [Food]
}
Alamofire.request(url)
.responseData { response in
switch response.result {
case .success(let data):
do {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let responseObject = try decoder.decode(FoodsResponse.self, from: data)
print(responseObject.foods)
} catch {
print(error)
}
case .failure(let error):
print(error)
}
}
This gets you completely out of the business of manually iterating through the results to map it to your objects.
Clearly, I assume your real response has more keys than just foods
, so you'd add whatever fields you needed to FoodsResponse
, but hopefully this illustrates the idea of letting JSONDecoder
parse the JSON into your model structures automatically.
For more information about JSONDecoder
and Codable
types, see Encoding and Decoding Custom Types.
By the way, my example FoodResponse
structure prompted some question why I didn't just assume the web service would return an array of Food
objects. Let me explain my rationale.
A more typical structure for FoodsResponse
in a web service response would be something like:
struct FoodsResponse: Codable {
let success: Bool
let error: String? // only supplied if `success` was `false`
let foods: [Food]? // only supplied if `success` was `true`
}
In this structure, this response object can handle success scenarios, like:
{
"success": true,
"foods": [...]
}
Or failures:
{
"success": false,
"error": "No data found"
}
I think it best to have a structure that includes some common success Boolean, e.g. success
, that all well-formed responses include, and then have various properties that are filled in for successes or failures, respectively.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With