[Swift] JSON文字列から任意のオブジェクトへ変換する(JSONDecoderとCodableの利用)
こんにちは、@yoheiMuneです。
Swift4から
今日は、Swift4におけるJSONの扱いをブログに書きたい次第です。
なお、オブジェクトの型を用意するのが面倒と思うかもしれませんが、実際の開発ではAPIのレスポンス結果は特定の形を想定しているので、このようなクラスを作成する方が実装効率は良いです。
例えば、以下のように
Codable - Swift Standard Library | Apple Developer Documentation(公式サイト)
JSONDecoder - Foundation | Apple Developer Documentation(公式サイト)
Encoding and Decoding Custom Types | Apple Developer Documentation(公式サイト)
[Swift 4] SwiftyJSONを使わずにシンプルにJSONをデータ構造化する | Developers.IO
Ultimate Guide to JSON Parsing with Swift 4
Codableで色々なJSONに対応する - Qiita
最後になりますが本ブログでは、フロントエンド、Swift、PHP、Node.js、Python、Linux、Java、インフラ、Go言語、機械学習、などの技術トピックを発信をしていきます。「プログラミングで困ったその時の、解決の糸口に!」そんな目標でブログを書き続けています。ぜひ、本ブログのRSSやTwitterをフォローして貰えたら嬉しいです ^ ^
最後までご覧頂きましてありがとうございました!
Swift4から
Codable
が追加されて、JSON文字列から任意のオブジェクトに簡単に変換できるようになりました。今日はその方法をブログに書きたいと思います。目次
対象のバージョン
このブログでの記載は、Swift4
以上を対象としています。何がしたいのか
Swift3以前だと、JSON文字列からデータを取り出すためにSwiftyJSONなどを使う必要があり、なかなか煩雑でした。しかしSwift4から追加されたCodable
とJSONDecoder
を用いることで、簡単にJSON文字列をデコードすることができます。今日は、Swift4におけるJSONの扱いをブログに書きたい次第です。
JSON文字列 -> 任意のオブジェクトへの変換
それではここから具体的な使い方を見ていきたいと思います。基本的な使い方
例えば以下のようなJSON文字列があったとします。let jsonStr = """ { "name" : "Munesada", "age" : 32 } """これを読み込んで、以下のデータ型にマッピングしたいとします。
struct User: Codable { // Codableインターフェースを実装する let name: String let age: Int }ここでポイントは
Codable
を継承することです。この状態で、以下のようにJSONDecoder
を使うことで、JSON文字列をUser
オブジェクトに変換することができます。// String -> Data に変換 let jsonData = jsonStr.data(using: .utf8) // JSONをデコード let user = try! JSONDecoder().decode(User.self, from: jsonData!) // 結果を表示してみる. print("name: \(user.name)") // Munesada print("age: \(user.age)") // 32このように、簡単にJSON文字列をオブジェクトに変換することができます。
なお、オブジェクトの型を用意するのが面倒と思うかもしれませんが、実際の開発ではAPIのレスポンス結果は特定の形を想定しているので、このようなクラスを作成する方が実装効率は良いです。
オプショナル型を扱う
API結果(JSON)によっては、一部のプロパティが省略される場合があります。その場合には、省略されるプロパティをオプショナル型として定義することで取り込むことができます。struct User: Codable { let name: String let age: Int let message: String? // オプショナル型にする }この場合、
message
は省略されたらnilになります。// messageが省略された場合 let jsonStr = """ { "name" : "Munesada", "age" : 32 } """ let jsonData = jsonStr.data(using: .utf8) let user = try! JSONDecoder().decode(User.self, from: jsonData!) // デコード結果はnilになる. print("message: \(user.message ?? "ないよー")") // ないよー
ネストにも対応できる
API結果(JSON)が1階層であることは少なく、2階層以上あることが多いと思います。JSONデコードはネストし構造にも対応できます。例えば、以下のように
Group -> User
とネストしているとします。struct Group: Codable { let groupName: String // Userを保持している(=ネスト) let users: [User] }この場合にも、今まで同じような実装でデコードが可能です。
// ネストされたJSON let jsonStr = """ { "groupName": "グループ名", "users" : [{ "name" : "Munesada", "age" : 32 }, { "name" : "Yamada", "age" : 28 }] } """ let jsonData = jsonStr.data(using: .utf8) let group = try! JSONDecoder().decode(Group.self, from: jsonData!) // 結果の確認. print("groupName: \(group.groupName)") // グループ名 print("users: \(group.users)") // users: [User(name: "Munesada", age: 32, message: nil), User(name: "Yamada", age: 28, message: nil)]
ルートが配列の場合
API結果について、ルートが以下のように配列である場合も対応が可能です。// ルートがArrayの場合 let jsonStr = """ [ { "name" : "Yohei", "age" : 32 }, { "name" : "Kengo", "age" : 42 } ] """この場合は、
decode
関数に渡す形を[User].self
とします。let jsonData = jsonStr.data(using: .utf8) let users = try! JSONDecoder().decode([User].self, from: jsonData!) print("users: \(users)")
Date型へのパース
Date型へのパースも機能として提供されています。例えば以下の構造体にマッピングしたいとします。// Date型のフィールドを保持する構造体 struct MyDate: Codable { let dt: Date }JSONは以下の内容とします。
let jsonStr = """ { "dt" : "2018-03-03T12:13:31Z" } """このデータをデコードする場合に、JSONDecoderのインスタンスで
dateDecodingStrategy
を指定することで、日付型へマッピングできるようになります。let jsonData = jsonStr.data(using: .utf8) let decoder = JSONDecoder() decoder.dateDecodingStrategy = .iso8601 // 日付フォーマットを指定 // 後は普通にデコードする. let myDate = try! decoder.decode(MyDate.self, from: jsonData!) print("myDate: \(myDate)")
dateDecodingStrategy
で指定可能な値は、公式ドキュメントを参照ください。参考資料
CodableとJSONDecoderについて、以下の資料が参考になります。ありがとうございます。Codable - Swift Standard Library | Apple Developer Documentation(公式サイト)
JSONDecoder - Foundation | Apple Developer Documentation(公式サイト)
Encoding and Decoding Custom Types | Apple Developer Documentation(公式サイト)
[Swift 4] SwiftyJSONを使わずにシンプルにJSONをデータ構造化する | Developers.IO
Ultimate Guide to JSON Parsing with Swift 4
Codableで色々なJSONに対応する - Qiita
最後に
今回は構造体(struct)へマッピングしましたが、クラス(class)にも同じようにマッピング可能です。形のあるデータ構造へ簡単にマッピングできるのは嬉しいですね。最後になりますが本ブログでは、フロントエンド、Swift、PHP、Node.js、Python、Linux、Java、インフラ、Go言語、機械学習、などの技術トピックを発信をしていきます。「プログラミングで困ったその時の、解決の糸口に!」そんな目標でブログを書き続けています。ぜひ、本ブログのRSSやTwitterをフォローして貰えたら嬉しいです ^ ^
最後までご覧頂きましてありがとうございました!