Search code examples
iosswiftalamofireobjectmapper

How to parse complex data using alamofire object mapper?


I am trying to parse JOSN data using Alamofire object mapper..Done with basic things but stuck with complex things like

1.How can I access values in "settings_data"? (which is best way to access nested object)

2.where can i define .GET, .POST method type and where we should pass parameter ? like for normal alamofire request we write as

  Alamofire.request(url, method: .get, parameters: nil, encoding: JSONEncoding.default)
            .responseJSON { response in

is there any good way to achieve the same?

JOSN Response

{
    "err": 0,
    "result": [{
        "id": 71930,
        "account_id": 40869,
        "status": "enabled",
        "settings_data": {
            "time_format": "12h",
            "timezone": "US/Pacific",
            "fingerprint_versions": {
                "browser.browser-js": 1
            },
            "integrations": {
                "jira": {},
                "datadog": {},
                "bitbucket": {},
                "github": {},
                "trello": {
                    "board_id": "xxx",
                    "enabled": true,
                    "access_token_user_id": 1234,
                    "list_id": "xxxxx"
                },
                "slack": {
                    "channel_id": "xxxx",
                    "enabled": true,
                    "access_token_user_id": "xx"
                },
                "webhook": {},
                "victorops": {},
                "asana": {},
                "pivotal": {},
                "campfire": {},
                "sprintly": {},
                "pagerduty": {},
                "hipchat": {},
                "email": {
                    "enabled": true
                },
                "flowdock": {}
            }
        },
        "date_created": 1468068105,
        "date_modified": 1493409629,
        "name": "Android_ParentApp"
    }, {
        "id": 71931,
        "account_id": 40869,
        "status": "enabled",
        "settings_data": {
            "time_format": "12h",
            "timezone": "US/Pacific",
            "fingerprint_versions": {
                "browser.browser-js": 1
            },
            "integrations": {
                "jira": {},
                "datadog": {},
                "bitbucket": {},
                "github": {},
                "trello": {
                    "board_id": "xxxx",
                    "enabled": true,
                    "access_token_user_id": 1234,
                    "list_id": "xxxxx"
                },
                "slack": {
                    "channel_id": "xxxxx",
                    "enabled": true,
                    "access_token_user_id": "xxx"
                },
                "webhook": {},
                "victorops": {},
                "asana": {},
                "pivotal": {},
                "campfire": {},
                "sprintly": {},
                "pagerduty": {},
                "hipchat": {},
                "email": {
                    "enabled": true
                },
                "flowdock": {}
            }
        },
        "date_created": 1468068142,
        "date_modified": 1493409658,
        "name": "Android_TeacherApp"
    }]
}

Model Class - Project.swift

import Foundation
import ObjectMapper

class Project: NSObject, Mappable {

    var projectId: Int?
    var accountId: Int?
    var dateCreated: Int?
    var dateModified: Int?
    var name: String?
    var status: String?

    override init() {
        super.init()
    }

    convenience required init?(map: Map) {
        self.init()
    }

    func mapping(map: Map) {
        projectId <- map["id"]
        accountId <- map["account_id"]
        dateCreated <- map["date_created"]
        dateModified <- map["date_modified"]
        name <- map["name"]
        status <- map["status"]
    }
}

ViewController.swift

import UIKit
import Alamofire
import AlamofireObjectMapper

class ViewController: UIViewController {

    var projects:[Project] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        fetchData()

    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func fetchData(){
        UIApplication.shared.isNetworkActivityIndicatorVisible = true
        let apiUrl = "https://raw.githubusercontent.com/javalnanda/AlamofireObjectMapperSample/master/AOMsample.json"
        Alamofire.request(apiUrl).validate().responseArray(keyPath: "result") { (response: DataResponse<[Project]>) in
            UIApplication.shared.isNetworkActivityIndicatorVisible = false
            switch response.result {
            case .success:
                print(response.result)
                self.projects = response.result.value ?? []
               // print("sss \(self.projects)")

                for project in self.projects {
                    print(  project.name ?? "")
                }
            case .failure(let error):
                print(error)
            }
        }
    }

}

Solution

  • The best way to implement these types of complex json is to split each subcategory to different objects and make them conform to protocol mappable. Then parse the values inside that function. See the example of SettingsModel with time_format and timezone parsed. You can implement the rest of the classes like this

        import Foundation
        import ObjectMapper
    
        class Project: NSObject, Mappable {
    
            var projectId: Int?
            var accountId: Int?
            var dateCreated: Int?
            var dateModified: Int?
            var name: String?
            var status: String?
            var settings: SettingsModel?
            override init() {
                super.init()
            }
    
            convenience required init?(map: Map) {
                self.init()
            }
    
            func mapping(map: Map) {
                projectId <- map["id"]
                accountId <- map["account_id"]
                dateCreated <- map["date_created"]
                dateModified <- map["date_modified"]
                name <- map["name"]
                status <- map["status"]
                settings <- map["settings_data"]
            }
        }
    
    
    import UIKit
    import ObjectMapper
    
    class SettingsModel: NSObject,Mappable {
    
         var time_format:String?
         var timezone:String?
    
         override init() {
            super.init()
        }
    
        convenience required init?(map: Map) {
            self.init()
        }
    
        func mapping(map: Map) {
           time_format <- map["time_format"]
           timezone <- map["timezone"]
    }
    }
    

    If you don't wish to create new objects you can parse like

    func mapping(map: Map) {
                    projectId <- map["id"]
                    accountId <- map["account_id"]
                    dateCreated <- map["date_created"]
                    dateModified <- map["date_modified"]
                    name <- map["name"]
                    status <- map["status"]
                    time_format <- map["settings_data.time_format"]
                    timezone <- map["settings_data.timezone"]
    
                }