简体   繁体   中英

Swift - Alamofire parse long JSON response

I've getting an response from Alamofire.POST like a long JSON, and it look like this:

 "name_srname": "AAA BBB",
        "playerData": {
            "userData": {
                "waypointNumber": null,
                "longitude": 33.333,
                "latitude": 33.333,
                "address": {
                    "street": "aaa",
                    "city": "aaaa",
                    "country": "EN",
                    "zipCode": "00-00"
                },
                "dataTracker": null
            },
            "userDetails": {
                "level": 1,
                "exp_amount": 21.161993612,
                "points_amount": 90,
                "items": {
                    "armor": "aa",
                    "weapon": "aa",
                    "ring": "aa",
                    "helmet": "aa"
                },
                "rawData": null,
                "userCreateDate": "2021-03-10T12:00:00",
                "userLastActivity": "2021-03-10T12:00:00",
                "isActive": null
            },
            "lastWaypoint": [
                {
                    "type": null,
                    "waypointNumber": "01",
                    "longitude": 33.333,
                    "latitude": 33.333,
                    "address": {
                        "street": "aa",
                        "city": "aa",
                        "country": "aa",
                        "zipCode": "00-00"
                    },
                    "addressRaw": "",
                    "lastWaypointCreate": "2021-03-10T07:00:00",
                    "lastWaypointBegin": "2021-03-10T07:00:00",
                    "inGeofenceRange": null
                }
            ],
            "GuildName": "Iaaaa",
            "rankName": "aaaa",
            "progress": 93,
            "isReady": true,
            "timeJoin": "2021-03-10T11:42:00.673"

Ok now when we know what we got just create a new Class to handle it, like in Android.


import Foundation

// MARK: - ClassElement
class ClassElement: Codable {
    let nameSrname: String
    let playerData: PlayerData

    enum CodingKeys: String, CodingKey {
        case nameSrname
        case playerData
    }

    init(nameSrname: String, playerData: PlayerData) {
        self.nameSrname = nameSrname
        self.playerData = playerData
    }
}

//
// To read values from URLs:
//
//   let task = URLSession.shared.playerDataTask(with: url) { playerData, response, error in
//     if let playerData = playerData {
//       ...
//     }
//   }
//   task.resume()

// MARK: - PlayerData
class PlayerData: Codable {
    let userData: UserData
    let userDetails: UserDetails
    let lastWaypoint: [LastWaypoint]
    let guildName, rankName: String
    let progress: Int
    let isReady: Bool
    let timeJoin: String

    enum CodingKeys: String, CodingKey {
        case userData, userDetails, lastWaypoint
        case guildName
        case rankName, progress, isReady, timeJoin
    }

    init(userData: UserData, userDetails: UserDetails, lastWaypoint: [LastWaypoint], guildName: String, rankName: String, progress: Int, isReady: Bool, timeJoin: String) {
        self.userData = userData
        self.userDetails = userDetails
        self.lastWaypoint = lastWaypoint
        self.guildName = guildName
        self.rankName = rankName
        self.progress = progress
        self.isReady = isReady
        self.timeJoin = timeJoin
    }
}

//
// To read values from URLs:
//
//   let task = URLSession.shared.lastWaypointTask(with: url) { lastWaypoint, response, error in
//     if let lastWaypoint = lastWaypoint {
//       ...
//     }
//   }
//   task.resume()

// MARK: - LastWaypoint
class LastWaypoint: Codable {
    let type: JSONNull?
    let waypointNumber: String
    let longitude, latitude: Double
    let address: Address
    let addressRaw, lastWaypointCreate, lastWaypointBegin: String
    let inGeofenceRange: JSONNull?

    init(type: JSONNull?, waypointNumber: String, longitude: Double, latitude: Double, address: Address, addressRaw: String, lastWaypointCreate: String, lastWaypointBegin: String, inGeofenceRange: JSONNull?) {
        self.type = type
        self.waypointNumber = waypointNumber
        self.longitude = longitude
        self.latitude = latitude
        self.address = address
        self.addressRaw = addressRaw
        self.lastWaypointCreate = lastWaypointCreate
        self.lastWaypointBegin = lastWaypointBegin
        self.inGeofenceRange = inGeofenceRange
    }
}

//
// To read values from URLs:
//
//   let task = URLSession.shared.addressTask(with: url) { address, response, error in
//     if let address = address {
//       ...
//     }
//   }
//   task.resume()

// MARK: - Address
class Address: Codable {
    let street, city, country, zipCode: String

    init(street: String, city: String, country: String, zipCode: String) {
        self.street = street
        self.city = city
        self.country = country
        self.zipCode = zipCode
    }
}

//
// To read values from URLs:
//
//   let task = URLSession.shared.userDataTask(with: url) { userData, response, error in
//     if let userData = userData {
//       ...
//     }
//   }
//   task.resume()

// MARK: - UserData
class UserData: Codable {
    let waypointNumber: JSONNull?
    let longitude: Double
    let latitude: Int
    let address: Address
    let dataTracker: JSONNull?

    init(waypointNumber: JSONNull?, longitude: Double, latitude: Int, address: Address, dataTracker: JSONNull?) {
        self.waypointNumber = waypointNumber
        self.longitude = longitude
        self.latitude = latitude
        self.address = address
        self.dataTracker = dataTracker
    }
}

//
// To read values from URLs:
//
//   let task = URLSession.shared.userDetailsTask(with: url) { userDetails, response, error in
//     if let userDetails = userDetails {
//       ...
//     }
//   }
//   task.resume()

// MARK: - UserDetails
class UserDetails: Codable {
    let level: Int
    let expAmount: Double
    let pointsAmount: Int
    let items: Items
    let rawData: JSONNull?
    let userCreateDate, userLastActivity: String
    let isActive: JSONNull?

    enum CodingKeys: String, CodingKey {
        case level
        case expAmount
        case pointsAmount
        case items, rawData, userCreateDate, userLastActivity, isActive
    }

    init(level: Int, expAmount: Double, pointsAmount: Int, items: Items, rawData: JSONNull?, userCreateDate: String, userLastActivity: String, isActive: JSONNull?) {
        self.level = level
        self.expAmount = expAmount
        self.pointsAmount = pointsAmount
        self.items = items
        self.rawData = rawData
        self.userCreateDate = userCreateDate
        self.userLastActivity = userLastActivity
        self.isActive = isActive
    }
}

//
// To read values from URLs:
//
//   let task = URLSession.shared.itemsTask(with: url) { items, response, error in
//     if let items = items {
//       ...
//     }
//   }
//   task.resume()

// MARK: - Items
class Items: Codable {
    let armor, weapon, ring, helmet: String

    init(armor: String, weapon: String, ring: String, helmet: String) {
        self.armor = armor
        self.weapon = weapon
        self.ring = ring
        self.helmet = helmet
    }
}

typealias Class = [ClassElement]

// MARK: - Helper functions for creating encoders and decoders

func newJSONDecoder() -> JSONDecoder {
    let decoder = JSONDecoder()
    if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {
        decoder.dateDecodingStrategy = .iso8601
    }
    return decoder
}

func newJSONEncoder() -> JSONEncoder {
    let encoder = JSONEncoder()
    if #available(iOS 10.0, OSX 10.12, tvOS 10.0, watchOS 3.0, *) {
        encoder.dateEncodingStrategy = .iso8601
    }
    return encoder
}

// MARK: - URLSession response handlers

extension URLSession {
    fileprivate func codableTask<T: Codable>(with url: URL, completionHandler: @escaping (T?, URLResponse?, Error?) -> Void) -> URLSessionDataTask {
        return self.dataTask(with: url) { data, response, error in
            guard let data = data, error == nil else {
                completionHandler(nil, response, error)
                return
            }
            completionHandler(try? newJSONDecoder().decode(T.self, from: data), response, nil)
        }
    }

    func classTask(with url: URL, completionHandler: @escaping (Class?, URLResponse?, Error?) -> Void) -> URLSessionDataTask {
        return self.codableTask(with: url, completionHandler: completionHandler)
    }
}

// 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 in the next point I want to handle it with Alamofire, and I've a code like:

        AF.request("URL", method: .post, parameters: parameters, encoding: JSONEncoding.default)
            .responseJSON { response in
                //print(response)
                
                var statusCode = response.response?.statusCode
                if (statusCode != 200){
                    self.view.makeToast("Something went wrong...");
                } else{
                   // self.view.makeToast("It's ok");
                    if let classResponse = response.data {
                        do {
                            let response = try JSONDecoder().decode(ClassElement.self, from: classResponse)
                            print(response)
                        } catch {
                            print(error.localizedDescription)
                        }
                         }
                    
                }
            }

And im getting error like "The data couldn't be read because it isn't in the correct format." Im new in Swift so im trying to use it like in a Android but I think I missunderstand something... Can someone help me? I just want to get every value from this response for example the response.playerData.userData.waypointNumber but I don't know how to receive it.

To close my old question. The problem why im getting the error was the fact, im getting the json list so my json parser will look like:

let response = try JSONDecoder().decode([ClassElement].self, from: classResponse)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM