Swift 4 Codable:将JSON返回String转换为Int / Date / Float
我正在浏览一些项目并删除JSON解析框架,因为使用Swift 4似乎很简单。我遇到了这个奇怪的JSON返回,其中Ints
和Dates
作为Strings
返回。
我用 Apple的网站 Swift 4查看了GrokSwift的Parsing JSON ,但我没有看到任何跳出来的东西:改变类型。
Apple的示例代码显示了如何更改密钥名称,但我很难弄清楚如何更改密钥类型。
这是它的样子:
{ "WaitTimes": [ { "CheckpointIndex": "1", "WaitTime": "1", "Created_Datetime": "10/17/2017 6:57:29 PM" }, { "CheckpointIndex": "2", "WaitTime": "6", "Created_Datetime": "10/12/2017 12:28:47 PM" }, { "CheckpointIndex": "0", "WaitTime": "8", "Created_Datetime": "9/26/2017 5:04:42 AM" } ] }
我已经使用CodingKey
将字典键重命名为符合Swift的条目,如下所示:
struct WaitTimeContainer: Codable { let waitTimes: [WaitTime] private enum CodingKeys: String, CodingKey { case waitTimes = "WaitTimes" } struct WaitTime: Codable { let checkpointIndex: String let waitTime: String let createdDateTime: String private enum CodingKeys: String, CodingKey { case checkpointIndex = "CheckpointIndex" case waitTime = "WaitTime" case createdDateTime = "Created_Datetime" } } }
这仍然留给我应该是Int
或Date
String
。 我如何使用Codable协议将包含Int/Date/Float
作为String
的JSON返回转换为Int/Date/Float
?
这还不可能,因为Swift团队在JSONDecoder中只提供了String to date解码器。
您可以随时手动解码:
struct WaitTimeContainer: Decodable { let waitTimes: [WaitTime] private enum CodingKeys: String, CodingKey { case waitTimes = "WaitTimes" } struct WaitTime:Decodable { let checkpointIndex: Int let waitTime: Float let createdDateTime: Date init(checkpointIndex: Int, waitTime: Float, createdDateTime:Date) { self.checkpointIndex = checkpointIndex self.waitTime = waitTime self.createdDateTime = createdDateTime } static let formatter: DateFormatter = { let formatter = DateFormatter() formatter.calendar = Calendar(identifier: .iso8601) formatter.locale = Locale(identifier: "en_US_POSIX") formatter.timeZone = TimeZone(secondsFromGMT: 0) formatter.dateFormat = "MM/dd/yyyy hh:mm:ss a" return formatter }() init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) let checkpointIndexString = try container.decode(String.self, forKey: .checkpointIndex) let checkpointIndex = Int(checkpointIndexString)! let waitTimeString = try container.decode(String.self, forKey: .waitTime) let waitTime = Float(waitTimeString)! let createdDateTimeString = try container.decode(String.self, forKey: .createdDateTime) let createdDateTime = WaitTime.formatter.date(from: createdDateTimeString)! self.init(checkpointIndex:checkpointIndex, waitTime:waitTime, createdDateTime:createdDateTime) } private enum CodingKeys: String, CodingKey { case checkpointIndex = "CheckpointIndex" case waitTime = "WaitTime" case createdDateTime = "Created_Datetime" } } }
public extension KeyedDecodingContainer { public func decode(_ type: Date.Type, forKey key: Key) throws -> Date { let dateString = try self.decode(String.self, forKey: key) let dateFormatter = DateFormatter() dateFormatter.dateFormat = "MM/dd/yyyy hh:mm:ss a" guard let date = dateFormatter.date(from: dateString) else { let context = DecodingError.Context(codingPath: codingPath, debugDescription: "Could not parse json key to a Date") throw DecodingError.dataCorrupted(context) } return date } }
用法: –
let date: Date = try container.decode(Date.self, forKey: . createdDateTime)