2017-10-24 24 views
2

Swift 4ではかなり簡単なので、いくつかのプロジェクトを行ってJSON構文解析フレームワークを削除しています。 IntsおよびDatesStringsとして返されます。Swift 4 Codable:JSONの文字列をInt/Date/Floatに変換する

私はGrokSwift's Parsing JSON with Swift 4,Apple's websiteを見ましたが、タイプを変更することはありません。

Apple's example codeはキー名を変更する方法を示していますが、キーの種類を変更する方法がわかりません。

ここのように見えるものです:次のように私は、スウィフト準拠のエントリに辞書のキーの名前を変更するCodingKeyを使用しました

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

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である必要があります。 Int/Date/FloatStringとして含むJSON戻り値をInt/Date/Floatに変換するにはどうすればよいですか?

+0

、これはまだ不可能です。https://stackoverflow.com/questions/44594652/swift- 4-json-decodable-simple-way-to-decode-type-change –

+1

@Adrian Created_Datetimeはサーバーに格納されるときはUTC時刻で、ローカル時刻ではないことを確認します。そうでない場合は、日付フォーマッタのタイムゾーンを0秒FromGMTに設定しないでください。分あなたの日付。 –

答えて

6

これはnot yet possibleです。スウィフトチームは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" 
     } 
    } 
} 
+1

恐ろしい!それは仕事を終えた! JSONの今後の返品については参考にしておきます。ありがとうございました! – Adrian

+0

@Adrian:私はあなたを助けることができてうれしいです。 –

0
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) 
+1

ほんの少しのメモ:Formatterを拡張してメソッドから静的なDateFormatterを作成する必要があります。また、ロケールを "en_US_POSIX"に設定する必要があります。それ以外の場合は、12時間ではなく24時間に設定されたユーザデバイスの時刻形式のために失敗する可能性があります。 –

+0

あなたのメソッド内に日付フォーマッタを本当に宣言したい場合は、開発者はカスタムdateFormatを渡します。 Btwでは、名前をdecodeDateに変更して、最初のパラメータタイプを削除することもできます:Date.Typeは不要です。 –

+0

デコードに失敗したキーと値を文字列補間を使用してdebugDescriptionに含めることもできます。 –

関連する問題