2

This is my JSON response:

[
    [
        {
            "id": 22,
            "request_id": "rqst5c12fc9e856ae1.06631647",
            "business_name": "Code Viable",
            "business_email": "code@viable.com",
            "title": "Apache Load/Ubuntu",
        }
    ],
    [
        {
            "id": 24,
            "request_id": "rqst5c130cae6f7609.41056231",
            "business_name": "Code Viable",
            "business_email": "code@viable.com",
            "title": "Load",
        }
    ]
]

This JSON structure got an array inside of an array, the object of the inner array is what I am trying to parse. Here is the my mapper:

struct JobResponseDataObject: Mappable {

    init?(map: Map) {

    }

    var id: Int?
    var requestId: String?
    var businessName: String?
    var businessEmail: String?

    mutating func mapping(map: Map) {

        id              <- map["id"]
        requestId       <- map["request_id"]
        businessName    <- map["business_name"]
        businessEmail   <- map["business_email"]

    }
}

I have tried create another mapper struct to hold the array of objects [JobResponseDataObject] and use Alamofire's responseArray with it, but it didn't work. I have also tried prefixing my json id with 0. but that didn't work too. Please help

Thank

Brendon Cheung
  • 995
  • 9
  • 29

3 Answers3

3

So here's the deal...Codable is a pretty cool protocol from Apple to handle parsing JSON responses from APIs. What you're getting back is an array of arrays, so your stuff's gonna be look like this:

[[ResponseObject]]

So anyway, you'd make a struct of your object, like so:

struct ResponseObject: Codable {
    let id: Int?
    let requestId: String?
    let businessName: String?
    let businessEmail: String?
    let title: String?
}

You'll note I changed the key name a bit (instead of request_id, I used requestId). The reason is JSONDecoder has a property called keyDecodingStrategy which presents an enum of canned decoding strategies you can select from. You'd do convertFromSnakeCase.

Here's code you can dump into a playground to tinker with. Basically, declare your struct, match it up to whatever the keys are in your JSON, declare a decoder, feed it a decoding strategy, and then decode it.

Here's how you could do an Alamofire call:

    private let backgroundThread = DispatchQueue(label: "background",
                                                 qos: .userInitiated,
                                                 attributes: .concurrent,
                                                 autoreleaseFrequency: .inherit,
                                                 target: nil)


    Alamofire.request(url).responseJSON(queue: backgroundThread) { (response) in
        guard response.result.error == nil else {
            print("KABOOM!")
            return
        }

        if let data = response.data {
            let decoder = JSONDecoder()
            decoder.keyDecodingStrategy = .convertFromSnakeCase

            do {
                let parsedResponse = try decoder.decode([[ResponseObject]].self, from: data)
                print(parsedResponse)
            } catch {
                print(error.localizedDescription)
            }
        }
    }

Here's code you can chuck in a playground.

import UIKit

let json = """
[
    [
        {
        "id": 22,
        "request_id": "rqst5c12fc9e856ae1.06631647",
        "business_name": "Code Viable",
        "business_email": "code@viable.com",
        "title": "Apache Load/Ubuntu",
        }
    ],
    [
        {
        "id": 24,
        "request_id": "rqst5c130cae6f7609.41056231",
        "business_name": "Code Viable",
        "business_email": "code@viable.com",
        "title": "Load",
        }
    ]
]
"""

struct ResponseObject: Codable {
    let id: Int?
    let requestId: String?
    let businessName: String?
    let businessEmail: String?
    let title: String?
}

if let data = json.data(using: .utf8) {
    let decoder = JSONDecoder()
    decoder.keyDecodingStrategy = .convertFromSnakeCase

    do {
        let parsedResponse = try decoder.decode([[ResponseObject]].self, from: data)
        print(parsedResponse)
    } catch {
        print(error.localizedDescription)
    }
}
Adrian
  • 16,233
  • 18
  • 112
  • 180
0

You should use this JobResponseDataObject struct as [[JobResponseDataObject]] instead of [JobResponseDataObject] - where you are making a property using this struct in your parent struct or class.

Sharad Paghadal
  • 2,089
  • 15
  • 29
-1

You can use Codable here for mapping the JSON response, The JobResponseDataObject struct should look like,

struct JobResponseDataObject: Codable {
    var id: Int?
    var requestId: String?
    var businessName: String?
    var businessEmail: String?
    var title: String?

    private enum CodingKeys: String, CodingKey {
        case id = "id"
        case requestId = "request_id"
        case businessName = "business_name"
        case businessEmail = "business_email"
        case title = "title"
    }
}

let json = JSON(responseJSON: jsonData)
    do {
        if let value = try? json.rawData(){
            let response = try! JSONDecoder().decode([[JobResponseDataObject]].self, from: value)
        }

    } catch {
        print(error.localizedDescription)
}
Bappaditya
  • 9,494
  • 3
  • 20
  • 29
  • There's no property called `businessModels` in the OP's question and the one you've declared doesn't conform to `Codable`. – Adrian Dec 15 '18 at 04:43
  • Why `Int16`? Also, you don’t need to declare the `CodingKeys` enum if your property names match the keys in JSON. – Losiowaty Dec 15 '18 at 14:38