Alamofire object mapper: how to parse nested array in swift - ios

This is my api response:
[
[
{
"id": 24,
"request_id": "rqst5c130cae6f7609.41056231",
"business_name": "Code Viable",
"business_email": "code#viable.com",
"title": "Load",
"details": "load",
"load_description": "load",
"amount_offered": "1",
"pickup_address": "load",
"dropoff_address": "load",
"timestamp": "2018-12-14 01:51:42"
}
],
[
{
"id": 27,
"request_id": "rqst5c1325881836d2.98441728",
"business_name": "Code Viable",
"business_email": "code#viable.com",
"title": "Load",
"details": "brendan",
"load_description": "test load for brendan",
"amount_offered": "1222",
"pickup_address": "Load",
"dropoff_address": "Load",
"timestamp": "2018-12-14 03:37:44"
}
]
]
As you can see, it is an array wrapped inside of an array, I have an object mapper setup already for the inner array, like this:
struct JobResponseDataObject: Mappable {
init?(map: Map) {
}
var id: Int?
var requestId: String?
var businessName: String?
var businessEmail: String?
var title: String?
var details: String?
var loadDescription: String?
var amountOffered: String?
var pickUpAddress: String?
var dropOffAddress: String?
var timestamp: String?
mutating func mapping(map: Map) {
id <- map["id"]
requestId <- map["request_id"]
businessName <- map["business_name"]
businessEmail <- map["business_email"]
title <- map["title"]
details <- map["details"]
loadDescription <- map["load_description"]
amountOffered <- map["amount_offered"]
pickUpAddress <- map["pickup_address"]
dropOffAddress <- map["dropoff_address"]
timestamp <- map["timestamp"]
}
}
If the parent has a name for it's child array, then I would create another mapper for the top level. But in this case, there is not a name for the outer array, what do I need to do to make the alamofire .responseArray call work?
Alamofire.request(JOB_REQUEST_BASE_URL, method: .post, parameters: parameter, encoding: URLEncoding(), headers: nil).responseArray { (response: DataResponse<[JobResponseDataObject]>) in
}
}
Thanks

Your JSON object have nested Array. So to parse that you can do it two ways. One way to do this is to parse it as nested array.
DataResponse<[[JobResponseDataObject]]>
And your code will looks like this.
Alamofire.request(JOB_REQUEST_BASE_URL, method: .post, parameters: parameter, encoding: URLEncoding(), headers: nil).responseArray { (response: DataResponse<[JobResponseDataObject]>) in
//...
}
Suggestion: So far what I can understand from JSON, it should not be in nested Array. If you only need to add one object in nested array, you can achieve same with simple array.
Second Way
If you only have one object in nested array. You can also parse it as following.
requestId <- map["0.request_id"]
"0." is here to get first object of inner array.
Hope this helps :)

Related

How to remove properties (key:values) from JSON object in Swift

I have JSON that looks like:
[
{
WWW: "2",
XXX: "2",
YYY: "3",
ZZZ: "4"
},
{
WWW: "2",
XXX: "5",
YYY: "6",
ZZZ: "7"
},
{
WWW: "2",
XXX: "2",
YYY: "2",
ZZZ: "3"
}
]
But I'm only interested in working with and Y and Z.
Howe can I remove the entire W and X columns either from the raw JSON or from the JSON in the form of an Array in SWIFT?
Only answers I can find such as here seem outdated. Thanks for suggestions.
Use:
dict["WWW"] = nil
dict["XXX"] = nil
or:
dict.removeValue(forKey: "WWW")
dict.removeValue(forKey: "XXX")
Better Approach would be using JSONEncoder and CodingKeys.
struct Model: Decodable {
var yyy, zzz: String
enum CodingKeys: String, CodingKey {
case yyy = "YYY", zzz = "ZZZ"
}
}
Define your struct to match what you want, and then decode it:
struct Value: Decodable {
enum CodingKeys: String, CodingKey {
case y = "YYY"
case z = "ZZZ"
}
var y: String
var z: String
}
let value = try JSONDecoder().decode([Value].self, from: json)
This will exclude any keys you don't include.

FIRInvalidArgumentException: Nested arrays are not supported

Currently, I'm trying to use Swift's codable protocol to add and read custom objects to and from Firebase's database. I've been following the instructions in these docs. However, when I try to write to the database, I'm getting an error "FIRInvalidArgumentException: Nested arrays are not supported". But aren't they supported? I saw another post on here from a couple of years ago that addressed a similar issue but I don't understand what I did wrong here.
These are the Swift struct representations that implement Codable:
struct List: Codable {
var title: String
var date: String
var description: String
var data: [SectionHeaders: Array<Item>] = [
.produce: [],
.seafood: [],
.meat: [],
.deli: [],
.bakery: [],
.pantry: [],
.dairy: [],
.frozen: [],
.other: []
]
enum CodingKeys: String, CodingKey {
case name
case date
case description
case data = "items"
}
struct Item: Codable {
var name: String?
var quantity: String?
}
enum SectionHeaders: Int, Codable {
case produce = 0, seafood, meat, deli, bakery, pantry, dairy, frozen, other, total
enum CodingKeys: String, CodingKey {
case produce = "produce"
case seafood = "seafood"
case meat = "meat"
case deli = "deli"
case bakery = "bakery"
case pantry = "pantry"
case dairy = "dairy"
case frozen = "frozen"
case other = "other"
}
}
And this is the data representation I'm aiming to get:
"title": String,
"date": String,
"description": String,
"items": [
"header1": [{
"name": String,
"quantity": String
},
{
"name": String,
"quantity": String
}
],
"header2": [{
"name": String,
"quantity": String
},
{
"name": String,
"quantity": String
}
]
]
Any help would be great! Thanks in advance!

Swift Codable not working for array of values

In my case I am trying to get JSON data using codable. Here, I can’t able to get data[Datum] values. How to get it and assign tableview data. I used to generate codable by using quicktype.io
JSON Data
{
"status": true,
"data": [
{
"id": "1",
"name": "one",
"description": "hello",
"date": "2020-08-05 11:37:52",
"startdate": "2019-08-05 11:37:52",
"createdby": "1",
"status": "0"
},
{
"id": "2",
"name": "two",
"description": "hi",
"date": "2020-08-05 11:37:52",
"startdate": "2019-08-05 11:37:52",
"createdby": "1",
"status": "0"
}
]
}
Codable Struct
// MARK: - Welcome
struct Welcome: Codable {
let status: Bool
let data: [Datum]
}
// MARK: - Datum
struct Datum: Codable {
let id, name, datumDescription, date: String
let startdate, createdby, status: String
enum CodingKeys: String, CodingKey {
case id, name
case datumDescription = "description"
case date, startdate, createdby, status
}
}
Code
let id: String = result.data.(Nothing Showing except Description)
let id: String = result.data.(Nothing Showing except Description)
It's not clear what "Nothing Showing except Description" means here, but the syntax you would expect would be:
let id: String = result.data[0].id // The id of the first Datum
data is an Array, so you'll need to subscript or iterate over it to get elements. For a tableview, you'd expect something like:
let id: String = result.data[indexPath.row].id
If this is not what you mean, you need to edit your question to make clear what your actual code is and the specific error message you receive.

Decoding Multiple JSON URLs into a Single Class

I'm attempting to decode multiple JSON URLs into a class. Since I'm using an API, I have no control over the fact that the JSON data is split into two URLs. Here is the problem statement:
I have a class called Student
JSON URL student_info.json contains a dictionary with all students and the Student instance constants A, and B.
JSON URL student_status.json contains Student instance variables C, D, and E.
I need to do the following:
Retrieve the dictionary of students from student_info.json to populate a collection of Students and instantiate them with attributes A and B.
Save this Student collection so that it is accessible throughout the rest of the app's lifecycle.
Retrieve the dictionary of student information from student_status.json and populate Student instance variables C, D, and E for each student in the collection.
From time to time, update the collection of students (in case any were dropped or added).
From time to time, update variables C, D, and E for each student in the collection.
Here are some example files:
File:
student_info.json
Content:
{
"last_updated": 1535936693,
"tyl": 10,
"data": {
"students": [
{
"student_id": "1",
"name": "John Appleseed",
},
{
"student_id": "2",
"name": "Jane Doe"
}
]
}
}
File:
student_status.json
Content:
{
"last_updated": 1535936693,
"tyl": 10,
"data": {
"students": [
{
"student_id": "1",
"number_of_classes": "10",
"GPA": "2.87",
"tuition_due": "237.33"
},
{
"student_id": "2",
"number_of_classes": "10",
"GPA": "2.87",
"tuition_due": "237.33"
}
]
}
}
File
Student.swift
Content
class Student {
var student_id: Int
var name: String
var numberOfClasses: Int?
var gpa: Double?
var tuitionDue: Double?
}

Get key of dictionary on JSON parse with SwiftyJSON

I want to get "key of dictionary" (that's what I called, not sure if it is right name) on this JSON
{
"People": {
"People with nice hair": {
"name": "Peter John",
"age": 12,
"books": [
{
"title": "Breaking Bad",
"release": "2011"
},
{
"title": "Twilight",
"release": "2012"
},
{
"title": "Gone Wild",
"release": "2013"
}
]
},
"People with jacket": {
"name": "Jason Bourne",
"age": 15,
"books": [
{
"title": "Breaking Bad",
"release": "2011"
},
{
"title": "Twilight",
"release": "2012"
},
{
"title": "Gone Wild",
"release": "2013"
}
]
}
}
}
First of all, I already created my People struct that will be used to map from those JSON.
Here is my people struct
struct People {
var peopleLooks:String?
var name:String?
var books = [Book]()
}
And here is my Book struct
struct Book {
var title:String?
var release:String?
}
From that JSON, I created engine with Alamofire and SwiftyJSON that will be called in my controller via completion handler
Alamofire.request(request).responseJSON { response in
if response.result.error == nil {
let json = JSON(response.result.value!)
success(json)
}
}
And here is what I do in my controller
Engine.instance.getPeople(request, success:(JSON?)->void),
success:{ (json) in
// getting all the json object
let jsonRecieve = JSON((json?.dictionaryObject)!)
// get list of people
let peoples = jsonRecieve["People"]
// from here, we try to map people into our struct that I don't know how.
}
My question is, how to map my peoples from jsonRecieve["People"] into my struct?
I want "People with nice hair" as a value of peopleLooks on my People struct. I thought "People with nice hair" is kind of key of dictionary or something, but I don't know how to get that.
Any help would be appreciated. Thank you!
While you iterate through dictionaries, for instance
for peeps in peoples
You can access key with
peeps.0
and value with
peeps.1
You can use key, value loop.
for (key,subJson):(String, JSON) in json["People"] {
// you can use key and subJson here.
}

Resources