gersey
gersey

Reputation: 57

Parsing Codable Responses with Alamofire

I using the Alamofire Framework, but I don't understand why the variables below are empty.

json:

{
    "ret": true,
    "text": "Oke!",
    "data": {
        "email": “[email protected]”,
        "nev": "text",
        "zip": "1234",
        "city": "London",
        "street": "text",
        "phone": "5555555555",
        "gdpr": "2"
    }
}

UserDataRootClass.swift:

struct UserDataRootClass : Codable {

        let data : UserDataData?
        let ret : Bool?
        let text : String?

        enum CodingKeys: String, CodingKey {
                case data = "data"
                case ret = "ret"
                case text = "text"
        }

        init(from decoder: Decoder) throws {
                let values = try decoder.container(keyedBy: CodingKeys.self)
                data = try? UserDataData(from: decoder)
                ret = try values.decodeIfPresent(Bool.self, forKey: .ret)
                text = try values.decodeIfPresent(String.self, forKey: .text)
        }

}

UserDataData.swift:

struct UserDataData : Codable {

        let city : String?
        let email : String?
        let gdpr : String?
        let nev : String?
        let phone : String?
        let street : String?
        let zip : String?

        enum CodingKeys: String, CodingKey {
                case city = "city"
                case email = "email"
                case gdpr = "gdpr"
                case nev = "nev"
                case phone = "phone"
                case street = "street"
                case zip = "zip"
        }

        init(from decoder: Decoder) throws {
                let values = try decoder.container(keyedBy: CodingKeys.self)
                city = try values.decodeIfPresent(String.self, forKey: .city)
                email = try values.decodeIfPresent(String.self, forKey: .email)
                gdpr = try values.decodeIfPresent(String.self, forKey: .gdpr)
                nev = try values.decodeIfPresent(String.self, forKey: .nev)
                phone = try values.decodeIfPresent(String.self, forKey: .phone)
                street = try values.decodeIfPresent(String.self, forKey: .street)
                zip = try values.decodeIfPresent(String.self, forKey: .zip)
        }

}

NetworkManager.swift:

func postLogin(urlString: String, completion: @escaping (UserDataRootClass?) -> Void) {
        Alamofire.request(urlString).response {
            response in
            guard let data = response.data else { return }
            do {
                let decoder = JSONDecoder()
                let loginRequest = try decoder.decode(UserDataRootClass.self, from: data)
               completion(loginRequest)
            } catch let error {
                print(error)
                completion(nil)
            }
        }
    }

LoginViewController.swift:

let networkManager = NetworkManager()
networkManager.postLogin(urlString: "http://demo.com") { (loginRequest) in

if((loginRequest?.ret)!) {
   print(loginRequest) // -> for log
   print(loginRequest?.data.phone)
   }

}

The log:

UserDataRootClass(data: Optional(.UserDataData(gdpr: nil, email: nil, zip: nil, nev: nil, phone: nil, city: nil, street: nil)), ret: Optional(true), text: Optional("Oke!"))

The loginRequest?.ret, and loginRequest?.text is good, but loginRequest?.data.email, loginRequest?.data.zip... is empty (nil)

Upvotes: 4

Views: 3966

Answers (1)

Kamran
Kamran

Reputation: 15238

You don't need to declare CodingKeys enum when the variable name's of your type are same as the json keys in api response. For example, in your case you have named all variables(inside UserDataRootClass and UserDataData) same as their respective json key so you can remove those enums.

struct UserDataData : Codable {

        let city : String?
        let email : String?
        let gdpr : String?
        let nev : String?
        let phone : String?
        let street : String?
        let zip : String?
}

struct UserDataRootClass : Codable {

        let data : UserDataData?
        let ret : Bool?
        let text : String?
}

Also, you don't need to implement init(from decoder: Decoder) throws { until you have to do some customization on any attribute.

Upvotes: 3

Related Questions