'Convert Array of Dictionary to custom object swift
I have:
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"
]
]
I want to add all this array of dictionary to my custom object like
let country:[Country] = countries
My custom object looks like this:
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
}
}
I understand that I need a loop thru the array but idk what is the next step. Would be great to have an example.
Solution 1:[1]
You should make your Country conform to Codable protocol, convert your dictionary to JSON data using JSONSerialization and then just decode the Data using JSONDecoder, note that you can set its keyDecodingStrategy property to convertFromSnakeCase auto avoid the need to declare custom coding keys like 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)
}
Country(name: "Afghanistan", dialCode: "+93", code: "AF")
Country(name: "Aland Islands", dialCode: "+358", code: "AX")
Country(name: "Albania", dialCode: "+355", code: "AL")
Country(name: "Algeria", dialCode: "+213", code: "DZ")
Solution 2:[2]
Not related but remove NSObject until you are required
That is very simple thing you just need to think a bit
Create Object like this
var arr = [Country]()
Now Loop your array of dictionary
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)
}
That's it You have converted array of dict to Custom Object
Hope it is helpful to you
Solution 3:[3]
You can use flatMap method of a list to produce the result:
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
}
}
A full example would be:
//: 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)
Solution 4:[4]
There are a lot of answers already, but I find that there are short comings with most of them. This is what I would suggest:
extension Country {
init?(fromDict dict: [String: Any]) {
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
}
}
If you just want to ignore invalid country dictionaries, that's even easier:
let countries = countryDictionaries.flatMap(Country.init(fromDict:))
Solution 5:[5]
Very simple and clear solution:
- Create custom initializer with param json
[String : Any]in your classCountry. - Init all variables of class using loop in custom initializer.
Try this code:
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
}
}
- Create an instance of class
Countriesusing element of arraycountriesand collect the same in separate arrayarrayOfCountries
Try this code:
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)
}
}
Solution 6:[6]
Create a custom country class with 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
}
}
Later you can map the dictionary into the array of country using
let _ = countries.flatMap { Country.init }
Solution 7:[7]
First you need to initialize an empty array type of 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)
}
Solution 8:[8]
You can map the dictionary into the array. As a dictionary always returns an optional value for key (the value is not guaranteed to exist) you need a guard to make sure you proceed only if that is the case.
In this sample solution I throw if any of the values are not there - but this is really up to you to decide.
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
}
Solution 9:[9]
Here is a useful extension that infers the type from the pre-defined return type:
extension Dictionary {
func castToObject<T: Decodable>() -> T? {
let json = try? JSONSerialization.data(withJSONObject: self)
return json == nil ? nil : try? JSONDecoder().decode(T.self, from: json!)
}
}
Usage would be:
struct Person: Decodable {
let name: String
}
let person: Person? = ["name": "John"].castToObject()
print(person?.name) // Optional("John")
Solution 10:[10]
you can use Array.foreach like this
countries.forEach{country.append(Country($0))}
and u may change init parameters of Country to [String: Any],
or cast $0 to [String: Any] and read ur values from it and send them to init
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | |
| Solution 3 | kender |
| Solution 4 | |
| Solution 5 | |
| Solution 6 | |
| Solution 7 | Alper |
| Solution 8 | |
| Solution 9 | |
| Solution 10 | Nizar Ahmed |
