Swift //将String Json文件转换为枚举大小写

时间:2018-01-13 19:19:59

标签: json swift

我的目标如下:

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
}

这是我的Alamofire请求的一部分:

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)

如何转换Json String" dishType"进入" DishType"我用enum创建的类型是为了正确填充我的Food实例吗?

1 个答案:

答案 0 :(得分:9)

您可能需要为枚举指定关联值:

enum DishType: String {
    case starter = "starter"
    case main    = "main"
    case desert  = "desert"
}

或者更简单:

enum DishType: String {
    case starter
    case main
    case desert
}

然后你可以这样做:

dishType = DishType(rawValue: string)

e.g。

if let dishTypeString = foodJson["type"].string,
    let dishType = DishType(rawValue: dishTypeString) {
        ...
}    

就个人而言,如果使用Swift 4,我将退休SwiftyJSON并使用原生JSONDecoder并声明您的类型为Codable。 (注意,我们仍然需要将DishType定义为具有关联值,如上所述。)

例如,让我们想象您的回答是这样的:

{
    "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"
        }
    ]
}

然后你可以像这样定义你的类型:

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
}

然后您可以像这样解析响应:

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)
        }
}

这使您完全脱离了手动迭代结果以将其映射到对象的业务。

显然,我认为您的真实答案包含的密钥多于foods,因此您需要添加FoodsResponse所需的任何字段,但希望这可以说明让{{1}自动将JSON解析到模型结构中。

有关JSONDecoderJSONDecoder类型的详细信息,请参阅Encoding and Decoding Custom Types

顺便说一句,我的示例Codable结构提示了一些问题,为什么我不假设Web服务会返回FoodResponse个对象的数组。让我解释一下我的理由。

Web服务响应中Food的更典型结构如下:

FoodsResponse

在此结构中,此响应对象可以处理成功方案,例如:

struct FoodsResponse: Codable {
    let success: Bool
    let error: String?   // only supplied if `success` was `false`
    let foods: [Food]?   // only supplied if `success` was `true`
}

或失败:

{
    "success": true,
    "foods": [...]
}

我认为最好有一个包含一些常见成功布尔的结构,例如{ "success": false, "error": "No data found" } ,所有格式良好的回复包括,然后分别为成功或失败填补各种属性。