首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Swift 4可编码:将JSON返回字符串转换为Int/Date/Float

Swift 4可编码:将JSON返回字符串转换为Int/Date/Float
EN

Stack Overflow用户
提问于 2017-10-24 02:51:30
回答 3查看 9.2K关注 0票数 15

我正在研究一些项目和删除JSON解析框架,因为使用Swift 4似乎非常简单,我遇到了这个奇怪的JSON返回,其中IntsDates作为Strings返回。

我看了一下GrokSwift用Swift 4解析JSON苹果网站,但是我没有看到任何跳出的东西:改变类型。

苹果的示例代码展示了如何更改密钥名,但我很难弄清楚如何更改密钥类型。

看上去是这样的:

代码语言:javascript
复制
{
    "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的条目,如下所示:

代码语言:javascript
复制
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"
    }
  }
}

这仍然留给我String,它应该是IntDate。如何使用可编码协议将包含Int/Date/Float作为String的JSON返回转换为Int/Date/Float

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-10-24 03:26:20

这是尚不可能,因为Swift团队在JSONDecoder中只提供了字符串到日期解码器。

不过,您始终可以手动解码:

代码语言:javascript
复制
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"
        }
    }
}
票数 14
EN

Stack Overflow用户

发布于 2017-10-24 03:55:28

代码语言:javascript
复制
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
}
}

用途:-

代码语言:javascript
复制
let date: Date = try container.decode(Date.self, forKey: . createdDateTime)
票数 0
EN

Stack Overflow用户

发布于 2022-08-29 18:53:16

让我建议两种方法:一种用于处理String支持的值,另一种用于处理可能以不同格式出现的日期。希望这个例子是自我解释的。

代码语言:javascript
复制
import Foundation

protocol StringRepresentable: CustomStringConvertible {
    init?(_ string: String)
}

extension Int: StringRepresentable {}
extension Double: StringRepresentable {}

struct StringBacked<Value: StringRepresentable>: Codable, CustomStringConvertible {
    var value: Value
    
    var description: String {
        value.description
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let string = try container.decode(String.self)
        
        guard let value = Value(string) else {
            throw DecodingError.dataCorruptedError(
                in: container,
                debugDescription: """
                Failed to convert an instance of \(Value.self) from "\(string)"
                """
            )
        }
        
        self.value = value
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(value.description)
    }
}

let decoder = JSONDecoder()

decoder.dateDecodingStrategy = .custom({ (decoder) -> Date in
    let container = try decoder.singleValueContainer()
    let dateStr = try container.decode(String.self)
    
    let formatters = [
        "yyyy-MM-dd",
        "yyyy-MM-dd'T'HH:mm:ssZZZZZ",
        "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ",
        "yyyy-MM-dd'T'HH:mm:ss'Z'",
        "yyyy-MM-dd'T'HH:mm:ss.SSS",
        "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
        "yyyy-MM-dd HH:mm:ss",
        "MM/dd/yyyy HH:mm:ss",
        "MM/dd/yyyy hh:mm:ss a"
    ].map { (format: String) -> DateFormatter in
        let formatter = DateFormatter()
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.dateFormat = format
        return formatter
    }
    
    for formatter in formatters {
        
        if let date = formatter.date(from: dateStr) {
            return date
        }
    }
    
    throw DecodingError.valueNotFound(String.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not parse json key: \(container.codingPath), value: \(dateStr) into a Date"))
})

// Test it with data:

let jsonData = """
{
    "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"
        }
    ]
}
""".data(using: .utf8)!

struct WaitTimeContainer: Codable {
    let waitTimes: [WaitTime]
    
    private enum CodingKeys: String, CodingKey {
        case waitTimes = "WaitTimes"
    }
    
    struct WaitTime: Codable {
        
        var checkpointIndex: Int {
            get { return checkpointIndexString.value }
            set { checkpointIndexString.value = newValue }
        }
        
        var waitTime: Double {
            get { return waitTimeString.value }
            set { waitTimeString.value = newValue }
        }
        
        let createdDateTime: Date
        
        private var checkpointIndexString: StringBacked<Int>
        private var waitTimeString: StringBacked<Double>
        
        private enum CodingKeys: String, CodingKey {
            case checkpointIndexString = "CheckpointIndex"
            case waitTimeString = "WaitTime"
            case createdDateTime = "Created_Datetime"
        }
    }
}

let waitTimeContainer = try decoder.decode(WaitTimeContainer.self, from: jsonData)
print(waitTimeContainer)
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46901445

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档