こんにちは、最近Swiftをやっていて、Scalaのコレクション操作が欲しくなってよくないなってなっています。
API等でJSON文字列を受け取って特定のオブジェクトなどにデータを入れたいみたいなのはよくあることだと思うのですが、
Swiftでやったのは初だったのでそのあたりのメモがてらの備忘録です。
SwiftのVersion
$swift --version Apple Swift version 5.2.4 (swiftlang-1103.0.32.9 clang-1103.0.32.53) Target: x86_64-apple-darwin19.5.0
StringやInt、Arrayのbind
文字列、数字や配列など、jsonにもある型は特段なにもしなくてもbindしてくれますね。
JSONDecoderになにも設定せずDecodableを実装したstructの変数名とkey名を合わせると勝手にbindしてくれました。
import Foundation let data = """ { "a": { "b": "xxx", "b2": ["xxx", "yyy"] } } """.data(using: .utf8)! struct A: Decodable { let a: B } struct B: Decodable { let b: String let b2: [String] } let decoder = JSONDecoder() let t1 = try decoder.decode(A.self, from: data) print(t1)
実行
$swift main1.swift A(a: main1.B(b: "xxx", b2: ["xxx", "yyy"]))
Date型のbind
やはりあるあるなのか、JSONDecoderにdateDecodingStrategyというものが用意されていました。
.iso8601フォーマットは既に用意されていて、そのフォーマットならそれを設定しておけば使えるみたいですね。
独自フォーマットにする場合はformattedメソッドにDateFormatterを渡してあげると良いみたいでした。
import Foundation let data = """ { "a": { "b": "xxx", "c": "2020-07-08T15:00:00+09:00", } } """.data(using: .utf8)! struct A: Decodable { let a: B } struct B: Decodable { let b: String let c: Date } let decoder = JSONDecoder() decoder.dateDecodingStrategy = .iso8601 let t1 = try decoder.decode(A.self, from: data) print(t1) decoder.dateDecodingStrategy = .formatted({ let f = DateFormatter() f.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ" return f }()) let t2 = try decoder.decode(A.self, from: data) print(t2)
実行
$swift main2.swift A(a: main2.B(b: "xxx", c: 2020-07-08 06:00:00 +0000)) A(a: main2.B(b: "xxx", c: 2020-07-08 06:00:00 +0000))
Enum型のbind
Enum型はEnum型にDecodableを実装して、文字列を元にしたいのであればStringを継承しておけば良い感じでした。
import Foundation let data = """ { "a": { "d": [ "hoge", "fuga", "piyo" ] } } """.data(using: .utf8)! struct A: Decodable { let a: B } struct B: Decodable { let d: Array<D> enum D: String, Decodable { case HOGE = "hoge" case FUGA = "fuga" case PIYO = "piyo" } } let decoder = JSONDecoder() let t1 = try decoder.decode(A.self, from: data) print(t1)
実行
$swift main3.swift
A(a: main3.B(d: [main3.B.D.HOGE, main3.B.D.FUGA, main3.B.D.PIYO]))
かなり簡単でしたね。
これで大体のものはAPIから内部のデータに変換できそうです。
めでたしめでたし。