Search code examples
iosjsonswiftalamofireobjectmapper

Alamofire ObjectMapper - Extract common fields from all models and map them


There are few fields common in all models returned by api. But they don't come as a separate object. They are there among other fields.

Example of two models :

Event :

[  
   {  
      "event":{  
         "id":3,
         "company_id":18,
         "archived":false,
         "created_by":229,
         "updated_by":229,
         "owner_id":229,
         "subject":"",
         "start_date":null,
         "end_date":null,
         "name":null,
         "name_class_name":"",
         "related_to":null,
         "related_to_class_name":"",
         "status":"",
         "created_at":"2018-05-07T01:59:38.921-04:00",
         "updated_at":"2018-05-07T01:59:38.921-04:00",
         "custom_nf":false
      }
   }
]  

Opportunity :

[  
   {  
      "opportunity":{  
         "id":4,
         "company_id":18,
         "archived":false,
         "created_by":229,
         "updated_by":229,
         "owner_id":229,
         "account_id":null,
         "name":"",
         "lead_source":"",
         "amount":null,
         "close_date":null,
         "probability":null,
         "stage":"",
         "created_at":"2018-05-07T01:49:55.441-04:00",
         "updated_at":"2018-05-07T01:49:55.441-04:00"
      }
   }
]

As shown, initial fields are common in both (all) models - id, company_id, archived, created_by and so on.
There are tons of projects I have worked with ObjectMapper but didn't encounter this before. I am fully aware of handling nested models, but this is a different case.
Though I can easily handle this by repeating all common fields in all models. But this doesn't sound good.
What I am looking is a way I can create a separate model class with all common fields. But the question is - how would I map that with api response using ObjectMapper ?

Just as an example, this is how I have created Opportunity model :

import UIKit
import ObjectMapper

class Opportunity: NSObject, Mappable {

    var id: Int?
    var companyId: Int?
    var archived: Int?
    var createdBy: Int?
    var updatedBy: Int?
    var ownerId: Int?
    var accountId: Int?
    var name: String?
    var leadSource: String?
    var amount: String?
    var closeDate: String?
    var probability: String?
    var stage: String?
    var createdAt: String?
    var updatedAt: String?

    required init?(map: Map) {

    }

     func mapping(map: Map) {
        self.id <- map["id"]
        self.companyId <- map["company_id"]
        self.archived <- map["archived"]
        self.createdBy <- map["created_by"]
        self.updatedBy <- map["updated_by"]
        self.ownerId <- map["owner_id"]
        self.accountId <- map["account_id"]
        self.name <- map["name"]
        self.leadSource <- map["lead_source"]
        self.amount <- map["amount"]
        self.closeDate <- map["close_date"]
        self.probability <- map["probability"]
        self.stage <- map["stage"]
        self.createdAt <- map["created_at"]
        self.updatedAt <- map["updated_at"]
    }
}

Solution

  • You can create base entity and put there common fields.

    Example:

    import UIKit
    import ObjectMapper
    
    class BaseEntity: NSObject, Mappable {
    
        var id: Int?
        var companyId: Int?
        var archived: Int?
        var createdBy: Int?
        var updatedBy: Int?
        var ownerId: Int?
        var name: String?
        var createdAt: String?
        var updatedAt: String?
    
        required init?(map: Map) {
    
        }
    
        func mapping(map: Map) {
            self.id <- map["id"]
            self.companyId <- map["company_id"]
            self.archived <- map["archived"]
            self.createdBy <- map["created_by"]
            self.updatedBy <- map["updated_by"]
            self.ownerId <- map["owner_id"]
            self.name <- map["name"]
            self.createdAt <- map["created_at"]
            self.updatedAt <- map["updated_at"]
        }
    
    }
    
    class Opportunity: BaseEntity {
    
        var accountId: Int?
        var leadSource: String?
        var amount: String?
        var closeDate: String?
        var probability: String?
        var stage: String?
    
        required init?(map: Map) {
            super.init(map: map)
        }
    
        override func mapping(map: Map) {
            super.mapping(map: map)
            self.accountId <- map["account_id"]
            self.leadSource <- map["lead_source"]
            self.amount <- map["amount"]
            self.closeDate <- map["close_date"]
            self.probability <- map["probability"]
            self.stage <- map["stage"]
        }
    
    }
    

    Note: BaseEntity isn't good name, I think you can give better name.