Как использовать Alamofire с протоколом Codable и анализировать данные - PullRequest
0 голосов
/ 11 февраля 2020

Первое время с использованием протокола Codable, поэтому многое неясно. После прохождения нескольких уроков началось с Codable вещь для разбора данных. Ниже приведен код:

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)
    }

// Сетевой менеджер:

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)
                }
            }
    }

Теперь, это ответ:

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

Ниже json Ответ, который я пытаюсь проанализировать:

{
"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
    }
]   
} 

Я знаю, что что-то упустил, но даже потратив больше половины дня, я не понял, что не так и где. Пожалуйста, руководство.

Ответы [ 3 ]

0 голосов
/ 11 февраля 2020

Проблема в том, что в вашем верхнем JSON у вас есть единственное свойство «data» типа array.

Вы просите JSONDecoder декодировать объект JSON, содержащий только свойство «data» в объект Swift с именем «MyTasks» с сохраненными вами заданными свойствами (включая strDateDay).

Таким образом, декодер отправляет вам этот ответ, потому что он не может найти strDateDay в этом верхнем объекте.

Вы должны сделать топовый объект для десериализации. Что-то вроде:

struct MyResponse: Codable {
   var data: [MyTasks]
}

Затем просто передайте его своему JSONDecoder, как вы уже сделали:

let loginRequest = try decoder.decode(MyResponse.self, from: data)

Данные, которые вы отправляете в декодер, это ваш полный поток JSON ( свойство data объекта ответа Alamofire), а не только свойство data вашей структуры JSON.

0 голосов
/ 11 февраля 2020

Я бы предложил использовать CodyFire lib , поскольку он поддерживает Codable для всего, что связано с запросами.

Ваш POST-запрос с ним может выглядеть как

struct MyTasksPayload: JSONPayload {
    let param1: String
    let param2: String
}

struct MyTasksResponseModel: Codable {
    let strDateDay: String
    let strReminder: String
    let strRepetitions: String
    let name: String
}

let server = ServerURL(base: "https://server1.com", path: "v1")

APIRequest<[MyTasksResponseModel]>(server, "mytasks", payload: payloadModel)
    .method(.post)
    .onRequestStarted {
        // show HUD here
    }
    .onError {
        // hide hud and show error here
    }
    .onSuccess { tasks in
        // here's your decoded tasks
        // hide hud here
    }

Используйте APIRequest<[MyTasksResponseModel]> для декодирования массива

Используйте APIRequest для декодирования одного объекта

0 голосов
/ 11 февраля 2020

проблема с вашей структурой: имена свойств в структуре должны совпадать с данными json или, если вы хотите использовать пользовательское имя, вы должны использовать enum CodingKeys, чтобы преобразовать их по своему вкусу

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)
            }
        }
}

И еще одна вещь, имейте в виду, что вы знаете точный тип notes и делаете его необязательным, в противном случае возникает ошибка, типа не было, поэтому я добавил туда дополнительную строку.

Надеюсь, это поможет.

...