如何在swift中将JSON转换为结构类型数据?

时间:2017-11-20 23:47:24

标签: json swift json-deserialization

我有一个API供我的用户登录数据库。我使用以下代码将凭据发送到API,如果它们有效,我将获得有关用户信息的一些JSON类型数据。否则我得到一个字符串,说用户名或密码错误。 这是我的HTTTP Post请求:

let url = URL(string: "http://128.199.199.17:3000/api/login")!
        var request = URLRequest(url: url)
        request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
        request.httpMethod = "POST"
        let postString = "email=22222@gmail.com&password=123456"
        request.httpBody = postString.data(using: .utf8)
        let task = URLSession.shared.dataTask(with: request) { data, response, error in


            guard let data = data, error == nil else {
                print("error=\(String(describing: error))")
                return
            }

            if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
                print("statusCode should be 200, but is \(httpStatus.statusCode)")
                print("\(String(describing: response))")
            }

            let responseString = String(data: data, encoding: .utf8)
            print("responseString = \(responseString!)")
        }
        task.resume()

它工作正常,我在控制台中获得以下信息:

{
  "user_id": 2,
  "email": "22222@gmail.com",
  "password": "123456",
  "user_name": "number 2 name",
  "full_name": "danial kosarifar",
  "sex": "male",
  "height": 0,
  "weight": 0,
  "number_of_meal_per_day": 3,
  "water_amount": 0,
  "calories": 0,
  "number_of_hours_to_sleep_per_day": 3,
  "createdAt": "2017-11-14T17:23:31.000Z",
  "updatedAt": "2017-11-14T17:25:37.000Z"
}

我还创建了一个可解码的结构:

struct User : Decodable {

let user_id : Int
let email : String
let password : String
let username : String 
} 

我的问题不是将数据解码为字符串,而是如何解码它们,以便我可以将它们放入我已经定义的结构中。我对这个话题完全不熟悉,如果我的问题太多初学者,请耐心等待。 谢谢

2 个答案:

答案 0 :(得分:3)

Swift 4:

最好将struct创建为Codable,如下所示

struct User:Codable { //Because enum CodingKeys: String, CodingKey {

    let userID : Int
    let email : String
    let password : String
    let userName : String
    let fullName:String
    let sex:String
    let height:Int
    let weight:Int
    let numberOfMealPerDay:Int
    let waterAmount:Int
    let calories:Int
    let numberOfHoursToSleppPerDay:Int
    let createdAt:String
    let updatedAt:String

    enum CodingKeys: String, CodingKey {
        case userID = "user_id"
        case email
        case password
        case userName = "user_name"
        case fullName = "full_name"
        case sex
        case height
        case weight
        case numberOfMealPerDay = "number_of_meal_per_day"
        case waterAmount = "water_amount"
        case calories
        case numberOfHoursToSleppPerDay = "number_of_hours_to_sleep_per_day"
        case createdAt
        case updatedAt
    }
}

使用JSONDecoder

然后可以使用data解析closure task内的回复数据JSONDecoder。在此,userclass变量。即,var user:User?

if let json = try? JSONDecoder().decode(User.self, from: data!){

    self.user = json
}

注意:为了更好地理解,这是关于swift 4中JSON解析的video系列

答案 1 :(得分:1)

您可以将自定义初始化程序添加到用户结构中,该结构将json数据作为参数并将其抛出。您还需要创建一个自定义日期格式化程序来解析日期(您需要包含毫秒数)。请注意,如果您的json响应可能不包含某些键/值,则需要将该属性设置为可选:

因此,对于日期格式化程序,您可以使用此answer中的自定义日期格式化程序:

extension Formatter {
    static let iso8601: DateFormatter = {
        let formatter = DateFormatter()
        formatter.calendar = Calendar(identifier: .iso8601)
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.timeZone = TimeZone(secondsFromGMT: 0)
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"
        return formatter
    }()
}

您的用户结构应如下所示:

struct User: Codable {
    let id: Int
    let email: String
    let password: String
    let userName: String
    let fullName: String
    let sex: String
    let height: Int
    let weight: Int
    let mealsPerDay: Int
    let waterAmount: Int
    let calories: Int
    let hoursToSleepPerDay: Int
    let createdAt: Date
    let updatedAt: Date
    // you can provide different keys to your user struct properties
    private enum CodingKeys: String, CodingKey {
        case id = "user_id", email, password, userName = "user_name", fullName = "full_name", sex, height, weight, mealsPerDay = "number_of_meal_per_day", waterAmount = "water_amount", calories, hoursToSleepPerDay = "number_of_hours_to_sleep_per_day", createdAt, updatedAt
    }
    // custom initializer that takes the json data and throws in case of error
    init(data: Data) throws {
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .formatted(Formatter.iso8601)
        self = try decoder.decode(User.self, from: data)
    }
}

用法:

let data = Data("""
{
  "user_id": 2,
  "email": "22222@gmail.com",
  "password": "123456",
  "user_name": "number 2 name",
  "full_name": "danial kosarifar",
  "sex": "male",
  "height": 0,
  "weight": 0,
  "number_of_meal_per_day": 3,
  "water_amount": 0,
  "calories": 0,
  "number_of_hours_to_sleep_per_day": 3,
  "createdAt": "2017-11-14T17:23:31.000Z",
  "updatedAt": "2017-11-14T17:25:37.000Z"
}
""".utf8)

do {
    let user = try User(data: data)
    print(user)  // User(id: 2, email: "22222@gmail.com", password: "123456", userName: "number 2 name", fullName: "danial kosarifar", sex: "male", height: 0, weight: 0, mealsPerDay: 3, waterAmount: 0, calories: 0, hoursToSleepPerDay: 3, createdAt: 2017-11-14 17:23:31 +0000, updatedAt: 2017-11-14 17:25:37 +0000)\n"
} catch {
    print(error)
}