Search code examples
iosjsonswiftalamofireobjectmapper

Swift ObjectMapper: How to parse array inside of an array


This is my JSON response:

[
    [
        {
            "id": 22,
            "request_id": "rqst5c12fc9e856ae1.06631647",
            "business_name": "Code Viable",
            "business_email": "[email protected]",
            "title": "Apache Load/Ubuntu",
        }
    ],
    [
        {
            "id": 24,
            "request_id": "rqst5c130cae6f7609.41056231",
            "business_name": "Code Viable",
            "business_email": "[email protected]",
            "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


Solution

  • 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": "[email protected]",
            "title": "Apache Load/Ubuntu",
            }
        ],
        [
            {
            "id": 24,
            "request_id": "rqst5c130cae6f7609.41056231",
            "business_name": "Code Viable",
            "business_email": "[email protected]",
            "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)
        }
    }