Search code examples
iosswift5xcode11codabledecodable

How to use Alamofire with Codable protocol and parse data


Firs time using Codable protocol so many things not clear. After going through several tutorials started with the Codable thing to parse data. Below is the code:

struct MyTasks : Codable {
var strDateDay : String = ""
var strReminder : String = ""
var strRepetitions : String = ""
var name : String = ""
var strNotes : String = ""
var strUserId : String = ""

private enum CodingKeys: String, CodingKey {
    case strDateDay = "duedate"
    case strReminder = "reminder"
    case strRepetitions = "recurring"
    case name = "name"
    case strNotes = "notes"
    case strUserId = "userId"

}
}

let networkManager = DataManager()
    networkManager.postLogin(urlString: kGetMyTasks, header: header, jsonString: parameters as [String : AnyObject]) { (getMyTasks) in

        print(getMyTasks?.name as Any) // -> for log
        Common_Methods.hideHUD(view: self.view)
    }

// Network manager:

func postLogin(urlString: String, header: HTTPHeaders, jsonString:[String: AnyObject], completion: @escaping (MyTasks?) -> Void) {

           let apiString = KbaseURl + (kGetMyTasks as String)
           print(apiString)

                Alamofire.request(apiString, method: .post, parameters: jsonString , encoding: URLEncoding.default, headers:header).responseJSON
                { response in

                let topVC = UIApplication.shared.keyWindow?.rootViewController

                DispatchQueue.main.async {
                    //Common_Methods.showHUD(view: (topVC?.view)!)
                }

                guard let data = response.data else { return }
                do {
                    let decoder = JSONDecoder()
                    let loginRequest = try decoder.decode(MyTasks.self, from: data)
                    completion(loginRequest)
                } catch let error {
                    print(error)
                    completion(nil)
                }
            }
    }

Now, this is the response:

keyNotFound(CodingKeys(stringValue: "strDateDay", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"strDateDay\", intValue: nil) (\"strDateDay\").", underlyingError: nil))

Below is the json response i am trying to parse:

{
"data": [
    {
        "userId": 126,
        "name": "My task from postman ",
        "notes": null,
        "totalSteps": 0,
        "completedSteps": 0,
        "files": 0
    },
    {
        "userId": 126,
        "name": "My task from postman 1",
        "notes": null,
        "totalSteps": 0,
        "completedSteps": 0,
        "files": 0
    }
]   
} 

I know i am missing something but even after spending more than half day i haven't properly understood what is wrong and where. Please guide.


Solution

  • problem is with your struct the names of the properties in the struct should be match with json data or if you want to use custom name you should use enum CodingKeys to convert them to your liking

    struct MyTasks: Codable {
        let data: [Datum]
    }
    
    struct Datum: Codable {
        let userID: Int?
        let name: String
        let notes: String?
        let totalSteps, completedSteps, files: Int
    
        enum CodingKeys: String, CodingKey {
            case userID = "userId"
            case name, notes, totalSteps, completedSteps, files
        }
     }
    
        func postLogin(urlString: String, header: HTTPHeaders, jsonString:[String: AnyObject], completion: @escaping (MyTasks?) -> Void) {
    
           let apiString = KbaseURl + (kGetMyTasks as String)
           print(apiString)
    
            Alamofire.request(apiString, method: .post, parameters: jsonString , encoding: URLEncoding.default, headers:header).responseJSON
            { response in
    
                let topVC = UIApplication.shared.keyWindow?.rootViewController
    
                DispatchQueue.main.async {
                    //Common_Methods.showHUD(view: (topVC?.view)!)
                }
    
                guard let data = response.data else { return }
                do {
                    let decoder = JSONDecoder()
                    let loginRequest = try decoder.decode(MyTasks.self, from: data)
                    completion(loginRequest)
                } catch let error {
                    print(error)
                    completion(nil)
                }
            }
    }
    

    And one more thing keep in mind that you know the exact type of notes and make it optional otherwise it rise error, there was no type so I put a optional String in there.

    Hope this will help.