Search code examples
iosswiftalamofirejsondecoder

Swift store data from a Webrequest into structures


First of all I'm really beginner in Swift. I'm stuck for hours on this.

Here is the problem, I'm using AlamoFire in order to make my request

func getListFiles(userId: String, page: Int)
{
    let parameters: Parameters = [
        "userId": userId,
        "page": page
    ]

    Alamofire.request(baseUrl + Endpoints.GET_RECORDS.rawValue, method: HTTPMethod.post, parameters: parameters)
        .responseData { response in
            if let result = response.result.value{
                do {
                    let data = try JSONDecoder().decode(ListFilesStruct.self, from: result)
                } catch {
                    print("\(error)")
                }
            }
    }
}

and I want to store data response in my structure "ListFilesStruct". But it enters in the "catch" and fails

Printing description of error:
▿ DecodingError
  ▿ typeMismatch : 2 elements
- .0 : Swift.Dictionary<Swift.String, Any>
▿ .1 : Context
  ▿ codingPath : 3 elements
    - 0 : CodingKeys(stringValue: "data", intValue: nil)
    ▿ 1 : _JSONKey(stringValue: "Index 6", intValue: 6)
      - stringValue : "Index 6"
      ▿ intValue : Optional<Int>
        - some : 6
    - 2 : CodingKeys(stringValue: "expert", intValue: nil)
  - debugDescription : "Expected to decode Dictionary<String, Any> but found a string/data instead."
  - underlyingError : nil

Here is the main structure, I want an array of FileDetail

struct ListFilesStruct: Codable
{
    var success: Bool?
    var data: [FileDetail]?
}

struct FileDetail: Codable
{
    var id: String?
    var expert: FileElement?
}

And it exactly fails because of FileElement structure , I don't know why

struct FileElement: Codable
{
    var id: String?
    var role_id: String?
    var avatar: String?
    var nom: String?
    var prenom: String?  
}

I really want to store Webservice data like that , thanks

EDIT : Expected JSON :

{
"success": true,
"data": [
    {
        "id": "A19007994",
        "expert": {
            "id": "74EJEEZM",
            "role_id": "EXPERT",
            "avatar": null,
            "nom": "METRTALZ",
            "prenom": "JEREMIE",
        }
     }
 ]
 }

Solution

  • Use below struct for your expected json

    class MyCustomJSON: Codable {
        let success: Bool
        let data: [Datum]
    
        enum CodingKeys: String, CodingKey {
            case success = "success"
            case data = "data"
        }
    
        init(success: Bool, data: [Datum]) {
            self.success = success
            self.data = data
        }
    }
    
    class Datum: Codable {
        let id: String
        let expert: Expert
    
        enum CodingKeys: String, CodingKey {
            case id = "id"
            case expert = "expert"
        }
    
        init(id: String, expert: Expert) {
            self.id = id
            self.expert = expert
        }
    }
    
    class Expert: Codable {
        let id: String
        let roleID: String
        let nom: String
        let prenom: String
    
        enum CodingKeys: String, CodingKey {
            case id = "id"
            case roleID = "role_id"
            case nom = "nom"
            case prenom = "prenom"
        }
    
        init(id: String, roleID: String, nom: String, prenom: String) {
            self.id = id
            self.roleID = roleID
            self.nom = nom
            self.prenom = prenom
        }
    }
    
    // MARK: Encode/decode helpers
    
    class JSONNull: Codable, Hashable {
    
        public static func == (lhs: JSONNull, rhs: JSONNull) -> Bool {
            return true
        }
    
        public var hashValue: Int {
            return 0
        }
    
        public init() {}
    
        public required init(from decoder: Decoder) throws {
            let container = try decoder.singleValueContainer()
            if !container.decodeNil() {
                throw DecodingError.typeMismatch(JSONNull.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for JSONNull"))
            }
        }
    
        public func encode(to encoder: Encoder) throws {
            var container = encoder.singleValueContainer()
            try container.encodeNil()
        }
    }
    

    and initialize like this

    do {
         let myCustomJSON = try JSONDecoder().decode(MyCustomJSON.self, from: jsonData)
    } catch {
      print("\(error)")
    }
    

    I tried my code in playground and everything works. enter image description here