将Dictionary of Dictionary转换为自定义对象swift

时间:2017-12-07 14:02:04

标签: ios swift

我有:

    let countries : [[String : Any]] = [
            [
                "name" : "Afghanistan",
                "dial_code": "+93",
                "code": "AF"
            ],
            [
                "name": "Aland Islands",
                "dial_code": "+358",
                "code": "AX"
            ],
            [
                "name": "Albania",
                "dial_code": "+355",
                "code": "AL"
            ],
            [
                "name": "Algeria",
                "dial_code": "+213",
                "code": "DZ"
            ]
]

我想将所有这些字典数组添加到我的自定义对象中,例如

let country:[Country] = countries

我的自定义对象如下所示:

class Country: NSObject {
        let name: String
        let dial_code : String
        let code: String

        init(name: String, dial_code: String, code: String) {
            self.name = name
            self.dial_code = dial_code
            self.code = code
        }
    }

我明白我需要一个通过数组的循环但是idk下一步是什么。有一个例子会很棒。

9 个答案:

答案 0 :(得分:14)

您应该使您的国家/地区符合​​Codable协议,使用JSONSerialization将字典转换为JSON数据,然后使用Data解码JSONDecoder,请注意您可以将其keyDecodingStrategy属性设置为convertFromSnakeCase会自动避免声明自定义编码密钥,例如dial_Code

struct Country: Codable {
    let name: String
    let dialCode : String
    let code: String
}
do {
    let json = try JSONSerialization.data(withJSONObject: countries)
    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .convertFromSnakeCase
    let decodedCountries = try decoder.decode([Country].self, from: json)
    decodedCountries.forEach{print($0)}
} catch {
    print(error)
}
  

国家(姓名:"阿富汗",拨号代码:" + 93",代码:" AF")

     

国家(姓名:" Aland Islands",dialCode:" + 358",代码:" AX")

     

国家(姓名:"阿尔巴尼亚",dialCode:" + 355",代码:" AL")

     

国家(名称:"阿尔及利亚",dialCode:" + 213",代码:" DZ")

答案 1 :(得分:5)

不相关,但在需要之前删除NSObject

这很简单,你只需要思考一下

像这样创建全局对象

var arr = [Country]()

现在循环你的字典数组

  for dict in countries {
      // Condition required to check for type safety :)
        guard let name = dict["name"] as? String, 
              let dialCode = dict["dial_code"] as? String, 
              let code = dict["code"] as? String else {
              print("Something is not well")
             continue
         }
        let object = Country(name: name, dial_code:dialCode, code:code)
         arr.append(object)
    }

它已经将dict数组转换为自定义对象

希望它对你有所帮助

答案 2 :(得分:3)

您可以使用列表的flatMap方法生成结果:

countries.flatMap { (v: [String: Any]) -> Country? in
    if let name = v["name"] as? String, 
       let dial = v["dial_code"] as? String, 
       let code = v["code"] as? String {
        return Country(name: name, dial_code: dial, code: code)
    } else {
        return nil
    }
}

一个完整的例子是:

//: Playground - noun: a place where people can play

import UIKit

let countries : [[String : Any]] = [
    [
        "name" : "Afghanistan",
        "dial_code": "+93",
        "code": "AF"
    ],
    [
        "name": "Aland Islands",
        "dial_code": "+358",
        "code": "AX"
    ],
    [
        "name": "Albania",
        "dial_code": "+355",
        "code": "AL"
    ],
    [
        "name": "Algeria",
        "dial_code": "+213",
        "code": "DZ"
    ]
]

class Country: NSObject {
    let name: String
    let dial_code : String
    let code: String

    init(name: String, dial_code: String, code: String) {
        self.name = name
        self.dial_code = dial_code
        self.code = code
    }
}

let cnt = countries.flatMap { (v: [String: Any]) -> Country? in
    if let name = v["name"] as? String, let dial = v["dial_code"] as? String, let code = v["code"] as? String {
        return Country(name: name, dial_code: dial, code: code)
    } else {
        return nil
    }
}

print (cnt)

答案 3 :(得分:1)

非常简单明了的解决方案:

  • 在班级[String : Any]中使用参数json Country创建自定义初始值设定项。
  • 使用自定义初始化程序中的循环初始化类的所有变量。

试试这段代码:

class Country: NSObject {
    var name: String = ""
    var dial_code: String = ""
    var code: String = ""

    // Sol: 1
    init(json: [String : Any]) {
        if let name = json["name"] as? String, let dial_code = json["dial_code"] as? String, let code = json["name"] as? String {
            self.name = name
            self.dial_code = dial_code
            self.code = code
        }
    }

    // or Sol: 2
    init(name: String, dial_code: String, code: String) {
        self.name = name
        self.dial_code = dial_code
        self.code = code
    }
}
  • 使用数组Countries的元素创建类countries的实例,并在单独的数组中收集arrayOfCountries

试试这段代码:

let countries : [[String : Any]] = [
    [
        "name" : "Afghanistan",
        "dial_code": "+93",
        "code": "AF"
    ],
    [
        "name": "Aland Islands",
        "dial_code": "+358",
        "code": "AX"
    ],
    [
        "name": "Albania",
        "dial_code": "+355",
        "code": "AL"
    ],
    [
        "name": "Algeria",
        "dial_code": "+213",
        "code": "DZ"
    ]
]

var arrayOfCountries = [Country]()

// Sol: 1
for json in countries {
    let country = Country(json: json)
    print("country name - \(country.name)")
    arrayOfCountries.append(country)
}

// Sol: 2
for json in countries {

    if let name = json["name"] as? String, let dial_code = json["dial_code"] as? String, let code = json["name"] as? String {
        let country = Country(name: name, dial_code: dial_code, code: code)
        print("country name - \(country.name)")
        arrayOfCountries.append(country)
    }

}

答案 4 :(得分:1)

已经有很多答案,但我发现其中大多数都有缺点。这就是我的建议:

extension Country {
    init?(fromDict: [String: String]) {
        guard let name = dict["name"] as? String, 
              let dialCode = dict["dial_code"] as? String, 
              let code = dict["code"] as? String else {
            return nil
        }
        self.init(name: name, dialCode: dialCode, code: code)
    }
}

let countries = countryDictionaries.map { dict -> Country in
    if let country = Country(fromDict: dict) { return Country }
    else {
        preconditionFailure("Tried to convert an invalid dict into a country")
        // TODO: handle error appropriately
    }
}

如果您只是想忽略无效的国家/地区词典,那就更容易了:

let countries = countryDictionaries.flatMap(Country.init(fromDict:))

答案 5 :(得分:0)

首先,您需要初始化一个空数组类型的Country Class

var countryArray = [Country]()
//then you have to loop thru the countries dictionary 
//and after casting them adding it to this empty array with class initializer  

countries.forEach { (dict) in

    countryArray.append(Country(name: dict["name"] as! String, dial_code: dict["dial_code"] as! String, code: dict["code"] as! String))

}
//this is how you reach to properties
countryArray.forEach { (country) in
    print(country.name)
}

答案 6 :(得分:0)

您可以将字典映射到数组中。由于字典总是返回键的可选值(不保证值存在),因此您需要一个警卫,以确保只有在这种情况下才能继续。

在这个示例解决方案中,如果没有任何值,我会抛出 - 但这取决于你自己决定。

struct AnError: Error {}

do {
    let countryObjects: [Country] = try countries.map {
        guard let name = $0["name"] as? String,
              let dial_code = $0["dial_code"] as? String,
              let code = $0["code"] as? String else {throw AnError()}

        return Country(name: name, dial_code: dial_code, code: code)
    }
}
catch {
    //something went worng - handle the error
}

答案 7 :(得分:0)

您可以像这样使用Array.foreach

countries.forEach{country.append(Country($0))}

您可以将init的{​​{1}}参数更改为Country, 或者将[String: Any]投射到$0并从中读取您的值并将其发送到[String: Any]

答案 8 :(得分:0)

使用param json创建自定义国家/地区类[String:Any]

class Country: NSObject {
    var name: String?
    var dialCode: String?
    var code: String?

    init(json: [String : Any]) {
       self.name = json["name"] as? String
       self.dialCode = json["dial_code"] as? String
       self.code = json["code"] as? String
    }
}

稍后您可以使用

将字典映射到国家/地区数组中
let _ = countries.flatMap { Country.init }