Swift 4 Codable Array's

前端 未结 4 1205
半阙折子戏
半阙折子戏 2021-02-02 14:04

So I have an API route that returns a JSON array of objects. For example:

[
    {\"firstname\": \"Tom\", \"lastname\": \"Smith\", \"age\": 31},
    {\"firstname\         


        
相关标签:
4条回答
  • 2021-02-02 14:50

    to decode to array, you've your response in a type alias for clarity:

    typealias ServiceResponseObject = [ResponseObject]

    but then you'll have to confirm Array to codable:

    extension Array: Decodable where Element: Decodable {}

    that should make it all work.

    0 讨论(0)
  • I managed to serialize data response to codable objects.

    As all you may have been familiar with converting json object [String: String] for example. That json object need to be converted to Data by using json.data(using: .utf8)!.

    With Alamofire, it is easy to get that data (or at least this kind of data worked for me, already compatible with .utf8 thing), I can just use this already available function

    func responseData(queue: DispatchQueue?, completionHandler: @escaping (DataResponse<Data>) -> Void) -> Self
    

    Then just use that data as input for the Decoder in the completionHandler

    let objek = try JSONDecoder().decode(T.self, from: data)
    

    You can also make this to some generic serialization function, with a little tweak, from the documentation

    Generic Response Object Serialization

    to this modification

    func responseCodable<T: Codable>(
        queue: DispatchQueue? = nil,
        completionHandler: @escaping (DataResponse<T>) -> Void)
        -> Self
    {
        let responseSerializer = DataResponseSerializer<T> { request, response, data, error in
            guard error == nil else { return .failure(BackendError.network(error: error!)) }
    
            guard let data = data else {
                return .failure(BackendError.objectSerialization(reason: "data is not valid"))
            }
    
    
            do{
                let objek = try JSONDecoder().decode(T.self, from: data!)
                return .success(objek)
            } catch let e {
                return .failure(BackendError.codableSerialization(error: e))
            }
    
        }
    
        return response(queue: queue, responseSerializer: responseSerializer, completionHandler: completionHandler)
    }
    

    Sample struct

    struct Fids: Codable {
    
       var Status: Status?
       var Airport: Airport?
       var Record: [FidsRecord]
    }
    

    Use the function this way

        Alamofire.request("http://whatever.com/zzz").responseCodable { (response: DataResponse<Fids>) in
            switch response.result{
            case .success(let value):
                print(value.Airport)
            // MARK: do whatever you want
            case .failure(let error):
                print(error)
                self.showToast(message: error.localizedDescription)
            }
        }
    
    0 讨论(0)
  • 2021-02-02 14:57

    Swift 5 Using Codable

    Alamofire Generic Response

    PersonModel.swift (create with SwiftyJsonAccelerator)

    import Foundation
    
    class PersonModel: Codable {
    
      enum CodingKeys: String, CodingKey {
        case age
        case firstname
        case lastname   }
    
      var age: Int?   var firstname: String?   var lastname: String?
    
      init (age: Int?, firstname: String?, lastname: String?) {
        self.age = age
        self.firstname = firstname
        self.lastname = lastname   }
    
      required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        age = try container.decodeIfPresent(Int.self, forKey: .age)
        firstname = try container.decodeIfPresent(String.self, forKey: .firstname)
        lastname = try container.decodeIfPresent(String.self, forKey: .lastname)   }
    
    }
    

    Generic Get Response

    func genericGET<T: Decodable>(urlString: String, completion: @escaping (T?) -> ()) {
    
    Alamofire.request(urlString)
        .responseJSON { response in
            // check for errors
            switch response.result {
            case .success(_):
    
                do {
                    let obj = try JSONDecoder().decode(T.self, from: response.data!)
                    completion(obj)
                } catch let jsonErr {
                    print("Failed to decode json:", jsonErr)
                }
    
                break
            case .failure(_):
    
    
                completion(nil)
    
                break
            }
    }
    
    }
    

    Call this method

    genericGET(urlString: "YOUR_URL") { (persons: [PersonModel]?) in
        print(persons?[0].firstname)
    }
    
    0 讨论(0)
  • 2021-02-02 14:59

    Update regarding Alamofire 5: responseJSONDecodable.

    struct Person: Codable {
        let firstName, lastName: String
        let age: Int
    
        enum CodingKeys : String, CodingKey {
            case firstName = "firstname"
            case lastName = "lastname"
            case age
        }
    }
    
    Alamofire.request(request).responseJSONDecodable { (response: DataResponse<Person>) in
        print(response)
    }
    

    Alamofire 4 won't add Codable support for now (see #2177), you can use this extension instead: https://github.com/Otbivnoe/CodableAlamofire.

    let jsonData = """
    [
        {"firstname": "Tom", "lastname": "Smith", "age": 31},
        {"firstname": "Bob", "lastname": "Smith", "age": 28}
    ]
    """.data(using: .utf8)!
    
    struct Person: Codable {
        let firstName, lastName: String
        let age: Int
    
        enum CodingKeys : String, CodingKey {
            case firstName = "firstname"
            case lastName = "lastname"
            case age
        }
    }
    
    let decoded = try! JSONDecoder().decode([Person].self, from: jsonData)
    

    Sample: http://swift.sandbox.bluemix.net/#/repl/59a4b4fad129044611590820

    Using CodableAlamofire:

    let decoder = JSONDecoder()
    Alamofire.request(url).responseDecodableObject(keyPath: nil, decoder: decoder) { (response: DataResponse<[Person]>) in
        let persons = response.result.value
        print(persons)
    }
    

    keypath corresponds to the path where the results are contained in the JSON structure. E.g:

    {
        "result": {
            "persons": [
                {"firstname": "Tom", "lastname": "Smith", "age": 31},
                {"firstname": "Bob", "lastname": "Smith", "age": 28}
            ]
        }
    }
    

    keypath => results.persons

    [
        {"firstname": "Tom", "lastname": "Smith", "age": 31},
        {"firstname": "Bob", "lastname": "Smith", "age": 28}
    ]
    

    keypath => nil (empty keypath throws an exception)

    0 讨论(0)
提交回复
热议问题