web-dev-qa-db-ja.com

Swift 4 Codable:JSON戻り文字列をInt / Date / Floatに変換する

Swift 4.で行うのは非常に簡単なように見えるので、いくつかのプロジェクトを実行し、JSON解析フレームワークを削除しています。IntsDatesStringsとして返されるこの奇妙なJSONリターンに遭遇しました。

GrokSwiftのJSONの解析Swift 4AppleのWebサイト )を見ましたが、タイプの変更に関して飛び出すものは見当たりません。 。

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"
    }
  }
}

それでも、StringまたはIntであるはずのDateが残ります。 Codableプロトコルを使用して、Int/Date/FloatStringとして含むJSONリターンをInt/Date/Floatに変換するにはどうすればよいですか?

9
Adrian

これは まだ可能ではありません as Swiftチームは、JSONDecoderで文字列から日付へのデコーダーのみを提供しています。

ただし、いつでも手動でデコードできます。

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"
        }
    }
}
9
Puneet Sharma
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)
0
Deep Parekh