Search code examples
swift4alamofireobjectmapper

Parse responseJSON to ObjectMapper


I'm currently making a migration from Android to iOS, better said Java to Swift, I got a generic response in JSON, but I'm not able to use it as an object and show it in the storyboard. I'm really new to Swift so I've been stuck for a while.

I've tried ObjectMapper and also JSON decode with no result at all.

I declared this response as I used in Java(Android)

class ResponseObjectMapper<T,R>: Mappable where T: Mappable,R:Mappable{

var data:T?
var message:String!
var error:R?

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

func mapping(map: Map) {
    data          <- map["data"]
    message          <- map["message"]
    error          <- map["error"]
}
}

class UserMapper :Mappable{
var email:String?
var fullName:String?
var id:CLong?
var phoneNumber:String?
var token:CLong?

required init?(_ map: Map) {
}

func mapping(map: Map) {
    email <- map["email"]
    fullName <- map["fullName"]
    id <- map["id"]
    phoneNumber <- map["phoneNumber"]
    token <- map["token"]
    phoneNumber <- map["phoneNumber"]
}
}    

In my Android project I use the Gson dependency and I was able to use my JSON as an object

class ErrorMapper:Mappable{

var message:String?
var code:Int?

required init?(_ map: Map) {
}

func mapping(map: Map) {
    message          <- map["message"]
    code          <- map["code"]
}

}

This is the Alamofire that gave me the JSON.

func login(params: [String:Any]){Alamofire.request
("http://192.168.0.192:8081/SpringBoot/user/login", method: .post, 
parameters: params,encoding: JSONEncoding.default, headers: 
headers).responseJSON {
            response in
            switch response.result {
            case .success:

                let response = Mapper<ResponseObjectMapper<UserMapper,ErrorMapper>>.map(JSONString: response.data)


                break
            case .failure(let error):

                print(error)
            }
        }
}

If I print the response with print(response) I got

SUCCESS: {
data =     {
    email = "[email protected]";
    fullName = "Victor Pozo";
    id = 6;
    phoneNumber = 099963212;
    token = 6;
};
error = "<null>";
message = SUCCESS;
}

and if I use this code I can got a result with key and value but I don't know how to use it as an object

if let result = response.result.value {
                    let responseDict = result as! [String : Any]
                    print(responseDict["data"])
                }

console:

Optional({
email = "[email protected]";
fullName = "Victor Pozo";
id = 6;
phoneNumber = 099963212;
token = 6;
})

I would like to use it in an Object, like user.token in a View Controller, probably I'm really confused, trying to map with generic attributes.

Type 'ResponseObjectMapper<UserMapper, ErrorMapper>' does not conform to protocol 'BaseMappable'

Solution

  • First of all you will need a Network Manager which uses Alamofire to make all your requests. I have made generalized one that looks something like this. You can modify it as you want.

    import Foundation
    import Alamofire
    import SwiftyJSON
    
    class NetworkHandler: NSObject {
    
    let publicURLHeaders : HTTPHeaders = [
        "Content-type" : "application/json"
    ]
    
    let privateURLHeaders : HTTPHeaders = [
        "Content-type" : "application/json",
        "Authorization" : ""
    ]
    
    enum RequestType {
        case publicURL
        case privateURL
    }
    
    func createNetworkRequestWithJSON(urlString : String , prametres : [String : Any], type : RequestType, completion:@escaping(JSON) -> Void) {
    
        let internetIsReachable = NetworkReachabilityManager()?.isReachable ?? false
        if !internetIsReachable {
            AlertViewManager.sharedInstance.showAlertFromWindow(title: "", message: "No internet connectivity.")
        } else {
            switch type {
            case .publicURL :
                commonRequest(urlString: baseURL+urlString, parameters: prametres, completion: completion, headers: publicURLHeaders)
                break
            case .privateURL:
                commonRequest(urlString: baseURL+urlString, parameters: prametres, completion: completion, headers: privateURLHeaders)
                break
            }
        }
    }
    
    func commonRequest(urlString : String, parameters : [String : Any], completion : @escaping (JSON) -> Void , headers : HTTPHeaders){
    
        print("urlString:"+urlString)
        print("headers:")
        print(headers)
        print("parameters:")
        print(parameters)
    
        let url = NSURL(string: urlString)
        var request = URLRequest(url: url! as URL)
        request.httpMethod = "POST"
        request.httpHeaders = headers
        request.timeoutInterval = 10
        let data = try! JSONSerialization.data(withJSONObject: parameters, options: JSONSerialization.WritingOptions.prettyPrinted)
    
        let json = NSString(data: data, encoding: String.Encoding.utf8.rawValue)
        if let json = json {
            print("parameters:")
            print(json)
        }
    
        request.httpBody = json!.data(using: String.Encoding.utf8.rawValue)
        let alamoRequest = AF.request(request as URLRequestConvertible)
        alamoRequest.validate(statusCode: 200..<300)
        alamoRequest.responseJSON{ response in
            print(response.response?.statusCode as Any )
            if let status = response.response?.statusCode {
                switch(status){
                case 201:
                    print("example success")
                    SwiftLoader.hide()
                case 200 :
                    if let json = response.value {
                        let jsonObject = JSON(json)
                        completion(jsonObject)
                    }
                default:
                    SwiftLoader.hide()
                    print("error with response status: \(status)")
                }
            }else{
                let jsonObject = JSON()
                completion(jsonObject)
                SwiftLoader.hide()
            }
        }
    }
    }
    

    After this when ever you need to make a request you can use this function. This will take in parameters if any needed and once the request is complete it will execute a call back function in which you can handle the response. The response here will be of SWIFTYJSON format.

    func makeNetworkRequest(){
        let networkHandler = NetworkHandler()
        var parameters : [String:String] = [:]
        parameters["email"] = usernameTextField.text
        parameters["pass"] = passwordTextField.text
        networkHandler.createNetworkRequestWithJSON(urlString: "http://192.168.0.192:8081/SpringBoot/user/login", prametres: parameters, type: .publicURL, completion: self.handleResponseForRequest)
    }
    
    
    func handleResponseForRequest(response: JSON){
        if let message = response["message"].string{
            if message == "SUCCESS"{
    
                if let email = response["data"]["email"].string{
                    //Do something with email.
                }
    
                if let fullName = response["data"]["fullName"].string{
                    //Do something with fullName.
                }
    
                if let id = response["data"]["id"].int{
                    //Do something with id.
                }
    
                if let phoneNumber = response["data"]["phoneNumber"].int64{
                    //Do something with phoneNumber.
                }
    
                if let token = response["data"]["token"].int{
                    //Do something with token.
                }
            }else{
                //Error
            }
        }
    }
    

    Hope this helps. Let me know if you get stuck anywhere.