Reputation: 391
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.
Upvotes: 18
Views: 26662
Reputation: 1394
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")
Upvotes: 2
Reputation: 63137
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:))
Upvotes: 4
Reputation: 16416
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
Upvotes: 7
Reputation: 236260
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")
Upvotes: 53
Reputation:
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 }
Upvotes: 1
Reputation: 79636
Very simple and clear solution:
[String : Any]
in your class Country
.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
}
}
Countries
using element of array countries
and collect the same in separate array arrayOfCountries
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)
}
}
Upvotes: 1
Reputation: 2547
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
}
Upvotes: 0
Reputation: 180
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
Upvotes: -1
Reputation: 87131
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)
Upvotes: 5
Reputation: 1425
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)
}
Upvotes: 0