Convert Encoded String To JSON Array in Swift - arrays

I have an Encoded String:
("[{"carMake":"Mercedes","phone":"03001234567","insurancePolicyNo":"0123456","email":"a#g.com","full_name":"Steven Fin","registrationNo":"02134","insuranceProvider":"Michael","carModel":"Benz"}, {"carMake":"Audi","phone":"03007654321","insurancePolicyNo":"654321","email":"b#g.com","full_name":"Flemming Smith","registrationNo":"4325","insuranceProvider":"Buttler","carModel":"A3"}]")
I want to convert this into JSON array like this:
[
{
"full_name": "Steven Finn",
"insuranceProvider": "Michael",
"insurancePolicyNo": "0123456",
"registrationNo": "02134",
"carMake": "Mercedes",
"carModel": "Benz",
"email": "a#g.com",
"phone": "03001234567"
},
{
"full_name": "Flemming Smith",
"insuranceProvider": "Buttler",
"insurancePolicyNo": "654321",
"registrationNo": "4325",
"carMake": "Audi",
"carModel": "A3",
"email": "b#g.com",
"phone": "03007654321"
}
]
After some searching, what I did was converting it to Dictionary, which results in:
[["registrationNo": 02134, "carModel": Benz, "phone": 03001234567, "email": a#g.com, "insuranceProvider": Michael, "insurancePolicyNo": 0123456, "carMake": Mercedes, "full_name": Steven Finn], ["carModel": A3, "insuranceProvider": Buttler, "carMake": Audi, "insurancePolicyNo": 654321, "full_name": Flemming Smith, "registrationNo": 4325, "phone": 03007654321, "email": b#g.com]]
Which is not the desired result.
Did anyone knows how to achieve my desired array?

your so called Encoded String is already json data. Try this to decode it into a Car model:
struct Car: Codable {
let carMake, phone, insurancePolicyNo, email: String
let full_name, registrationNo, insuranceProvider, carModel: String
}
struct ContentView: View {
var body: some View {
Text("testing")
.onAppear {
let str = """
[{"carMake":"Mercedes","phone":"03001234567","insurancePolicyNo":"0123456","email":"a#g.com","full_name":"Steven Fin","registrationNo":"02134","insuranceProvider":"Michael","carModel":"Benz"}, {"carMake":"Audi","phone":"03007654321","insurancePolicyNo":"654321","email":"b#g.com","full_name":"Flemming Smith","registrationNo":"4325","insuranceProvider":"Buttler","carModel":"A3"}]
"""
do {
let data = str.data(using: .utf8)!
let response = try JSONDecoder().decode([Car].self, from: data)
print("\n---> response \(response)")
} catch {
print(" error \(error)")
}

Related

How to make JSON from nested struct

I have a nested struct:
struct Order: Codable {
let foodList: [FoodList]
let name: String
let phone: String
let email: String
}
struct FoodList: Codable {
let foodName: String
let foodID: String
let foodAmount: Int
}
I need to make JSON from this struct. It have to be like this:
{
"name": "Name",
"phone": "+1 999 999 999 999",
"email": "email#email.email",
"foodList": [
{
"foodName": "Big Mac",
"foodID": "115",
"foodAmount": 2
},
{
"foodName": "Naggets",
"foodID": "221",
"foodAmount": 5
}
]
}
But I always get this JSON )
[
{
"email": "Name",
"phone": "+1 999 999 999 999",
"foodList": {
"foodAmount": 2,
"foodID": "115",
"foodName": "Big Mac"
},
"name": "email#email.email"
},
{
"email": "email#email.email",
"phone": "+1 999 999 999 999",
"foodList": {
"foodAmount": 5,
"foodID": "221",
"foodName": "Naggets"
},
"name": "Name"
}
]
In JSON it have to be 1 Person and array of selected food.
I code JSON to struct with this code:
let orderList = [OrderList]()
for index in 0..<subMenuList.count {
if subMenuList[index].foodList.foodSelectedAmount != 0 {
orderList.append(OrderList(
foodList: FoodListOrder(
foodName: subMenuList[index].foodList.foodName,
foodID: subMenuList[index].foodList.foodID,
foodAmount: subMenuList[index].foodList.foodSelectedAmount),
name: mainView.nameTextField.text!,
phone: mainView.phoneTextField.text!,
email: mainView.emailTextField.text!))
}
let jsonEncoder = JSONEncoder()
do {
let jsonData = try jsonEncoder.encode(orderList)
print(String(data: jsonData, encoding: .utf8)!)
} catch {
print(error)
}
Something wrong in "FOR" block and textfields... I think. I am appending person's data from textfields each time it loops.
Assuming Order is equal to OrderList and FoodList is equal to FoodListOrder you have to create first the FoodList array and then create the (single) Order object.
var foodList = [FoodList]()
for item in subMenuList { // don't use an index based loop if you actually don't need the index
if item.foodList.foodSelectedAmount != 0 {
foodList.append(FoodList(foodName: item.foodList.foodName,
foodID: item.foodList.foodID,
foodAmount: item.foodList.foodSelectedAmount)
}
}
let order = Order(foodList: foodList,
name: mainView.nameTextField.text!,
phone: mainView.phoneTextField.text!,
email: mainView.emailTextField.text!)
let jsonEncoder = JSONEncoder()
do {
let jsonData = try jsonEncoder.encode(order)
print(String(data: jsonData, encoding: .utf8)!)
} catch {
print(error)
}

How to format JSON correctly with arrays

I'm trying to send a JSON payload in my POST request but I'm not sure on how to format it correctly to use arrays. This below is what the correct JSON itself looks like:
{
"animal": "dog",
"contents": [{
"name": "daisy",
"VAL": "234.92133",
"age": 3
}]
}
I have this so far:
group := map[string]interface{}{
"animal": "dog",
"contents": map[string]interface{}{
"name": "daisy",
"VAL": "234.92133",
"age": 3,
},
}
But I can't figure out how to do array of contents (the square brackets), only the curly brackets from "contents".
The quick answer:
group := map[string]interface{}{
"animal": "dog",
"contents": []map[string]interface{}{
{
"name": "daisy",
"VAL": "234.92133",
"age": 3,
},
},
}
But as already said in the comments it is better (type safety) to use structs instead:
type Animal struct {
Type string `json:"animal"`
Contents []AnimalContent `json:"contents"`
}
type AnimalContent struct {
Name string `json:"name"`
Value string `json:"VAL"`
Age int `json:"age"`
}
Then create with:
group := Animal{
Type: "dog",
Contents: []AnimalContent{
{
Name: "daisy",
Value: "234.92133",
Age: 3,
},
},
}
// to transform to json format
bts, err := json.Marshal(group)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(bts))

Swift access a list in a list

["list": Optional([Optional(["phone": Optional("+51263153765"), "name": Optional("Peter Agent"), "__typename": Optional("User"), "email": Optional("peter#pety.com")]), Optional(["name": Optional("Thomas Agent"), "__typename": Optional("User"), "email": Optional("email#gmail.biz"), "phone": Optional("+1313131231")])]), "__typename": Optional("CompareUsers")]
How can I access the value of each element of each array in the [list Optional([..])]
So I can put use the value like so -->
let email: [String] = []
for contact in (the list) {
email.append(contact.email)
}
and same for the phone and the name, if someone got a big brain related to swift please help.
let listDictionary = ["list": Optional([Optional(["phone": Optional("+51263153765"),
"name": Optional("Peter Agent"),
"__typename": Optional("User"),
"email": Optional("peter#pety.com")]),
Optional(["name": Optional("Thomas Agent"),
"__typename": Optional("User"),
"email": Optional("email#gmail.biz"),
"phone": Optional("+1313131231")])]),
"__typename": Optional("CompareUsers")]
if let listArray = listDictionary["list"] {
for data in listArray {
if let personData = data {
if let phone = personData["phone"], let name = personData["name"], let email = personData["email"], let type = personData["__typename"] {
print("User: \(name) of type: \(type), has phone number: \(phone) and email: \(email)")
}
}
}
}

Decode a JSON array

I'm just learning the Swift Decodable protocol and am running into a problem. I am able to decode one json object into a swift object, but am stuck with decoding an array.
What goes well:
imagine following json:
let json = """
{
"all" : {
"_id": "59951d5ef2db18002031693c",
"text": "America’s cats, including housecats that adventure outdoors and feral cats, kill between 1.3 billion and 4.0 billion birds in a year.",
"type": "cat",
"user": {
"_id": "5a9ac18c7478810ea6c06381",
"name": {
"first": "Alex",
"last": "Wohlbruck"
}
},
"upvotes": 4,
"userUpvoted": null
}
}
"""
let jsonData = json.data(using: .utf8)
I can decode it to a Fact object with following code:
enum Type: String, Decodable {
case cat = "cat"
}
struct Fact {
let id: String
let text: String
let type: Type
let upvotes: Int
enum CodingKeys: CodingKey {
case all
}
enum FactKeys: CodingKey {
case _id, text, type, upvotes
}
}
extension Fact: Decodable {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let allContainer = try container.nestedContainer(keyedBy: FactKeys.self, forKey: .all)
id = try allContainer.decode(String.self, forKey: ._id)
text = try allContainer.decode(String.self, forKey: .text)
type = try allContainer.decode(Type.self, forKey: .type)
upvotes = try allContainer.decode(Int.self, forKey: .upvotes)
}
}
let decoder = JSONDecoder()
let fact = try decoder.decode(Fact.self, from: jsonData!)
But the api is giving me an array of objects:
let json = """
{
"all": [
{
"_id": "59951d5ef2db18002031693c",
"text": "America’s cats, including housecats that adventure outdoors and feral cats, kill between 1.3 billion and 4.0 billion birds in a year.",
"type": "cat",
"user": {
"_id": "5a9ac18c7478810ea6c06381",
"name": {
"first": "Alex",
"last": "Wohlbruck"
}
},
"upvotes": 4,
"userUpvoted": null
},
{
"_id": "5b01a447c6914f0014cc9a30",
"text": "The special sensory organ called the Jacobson's organ allows a cat to have 14 times the sense of smell of a human. It consists of two fluid-filled sacs that connect to the cat's nasal cavity and is located on the roof of their mouth behind their teeth.",
"type": "cat",
"user": {
"_id": "5a9ac18c7478810ea6c06381",
"name": {
"first": "Alex",
"last": "Wohlbruck"
}
},
"upvotes": 4,
"userUpvoted": null
}
]
}
"""
let jsonData = json.data(using: .utf8)
And I want to store that in an allFacts array that hold my Fact objects
class Facts: ObservableObject {
#Published var allFacts = [Fact]()
}
let decoder = JSONDecoder()
let allFacts = try decoder.decode([Fact].self, from: jsonData!)
I'm using the same extension on my Fact struct. But it's giving me an error and I am totally lost for a second. Any idea how I can solve this ?
Do I need to create codingKeys for the class as well ?
Expected to decode Array<Any> but found a dictionary instead."
I recommend not to mess around with nested containers. This is less efficient than the default stuff. In your case you would have to use nestedUnkeyedContainer and iterate the array which is still more expensive.
Instead just add a root struct
let json = """
{
"all": [
{
"_id": "59951d5ef2db18002031693c",
"text": "America’s cats, including housecats that adventure outdoors and feral cats, kill between 1.3 billion and 4.0 billion birds in a year.",
"type": "cat",
"user": {
"_id": "5a9ac18c7478810ea6c06381",
"name": {
"first": "Alex",
"last": "Wohlbruck"
}
},
"upvotes": 4,
"userUpvoted": null
},
{
"_id": "5b01a447c6914f0014cc9a30",
"text": "The special sensory organ called the Jacobson's organ allows a cat to have 14 times the sense of smell of a human. It consists of two fluid-filled sacs that connect to the cat's nasal cavity and is located on the roof of their mouth behind their teeth.",
"type": "cat",
"user": {
"_id": "5a9ac18c7478810ea6c06381",
"name": {
"first": "Alex",
"last": "Wohlbruck"
}
},
"upvotes": 4,
"userUpvoted": null
}
]
}
"""
let jsonData = Data(json.utf8)
enum Type: String, Decodable {
case cat
}
struct Root : Decodable {
let all : [Fact]
}
struct Fact : Decodable {
let id: String
let text: String
let type: Type
let upvotes: Int
enum CodingKeys : String, CodingKey {
case id = "_id", text, type, upvotes
}
}
let decoder = JSONDecoder()
let root = try decoder.decode(Root.self, from: jsonData)
print(root.all)

How to get JSON array value in Swift using Codable

I'm having trouble getting the direction values from the following JSON:
"routeOptions": [
{
"name": "Jubilee",
"directions": [
"Wembley Park Underground Station",
"Stanmore Underground Station"
],
"lineIdentifier": {
"id": "jubilee",
"name": "Jubilee",
"uri": "/Line/jubilee",
"type": "Line",
"routeType": "Unknown",
"status": "Unknown"
}
}
]
I believe the directions is a JSON array, which at the moment I'm using Codable as below. I've managed to get the routeOptions name but can't seem to figure out how to get the directions as there's no specific key variable. Please can someone help?
struct RouteOptions: Codable {
let name: String?
let directions: [Directions]?
init(name: String, directions: [Directions]) {
self.name = name
self.directions = directions
}}
struct Directions: Codable {}
You need to handle directions as an array of String
struct RouteOptions: Codable {
let name: String
let directions: [String]
}
Here is an example where I fixed the json to be correct
let data = """
{ "routeOptions": [
{
"name": "Jubilee",
"directions": [
"Wembley Park Underground Station",
"Stanmore Underground Station"
],
"lineIdentifier": {
"id": "jubilee",
"name": "Jubilee",
"uri": "/Line/jubilee",
"type": "Line",
"routeType": "Unknown",
"status": "Unknown"
}
}
]}
""".data(using: .utf8)!
struct Root: Decodable {
let routeOptions: [RouteOptions]
}
struct RouteOptions: Codable {
let name: String
let directions: [String]
}
do {
let result = try JSONDecoder().decode(Root.self, from: data)
print(result.routeOptions)
} catch {
print(error)
}

Resources