【Swift】JSONデータをエンコードする方法!JSONEncoderクラスの使い方

この記事からわかること
- SwiftでJSONファイルを操作するには?
- エンコードする方法
- JSONEncoderの使い方
- 構造体をJSONデータに変換する方法
index
[open]
\ アプリをリリースしました /
Swiftの構造体をJSONデータに変換する方法をまとめていきたいと思います。
JSONファイルとは?
「JSONファイル」とはJavaScriptのオブジェクト形式の記法に準拠した構造で拡張子に「.json」が用いられるテキストデータファイルのことです。様々なプログラミング言語でも扱いが可能ながらもテキストファイルなので軽量なのが大きなメリットです。ちなみにJSONは「JavaScript Object Notation(記法)」の略称です。
JSON形式のデータ
{
"person": [
{
"name": "Ame Tsubaki",
"age": 18,
"hobby": ["旅行", "料理", { "web制作": ["HTML", "CSS", "php"] }]
},
{
"name": "Yoshida Takashi",
"age": 21,
"hobby": ["読書", "ランニング", "テニス"]
}
]
}
中身は配列と連想配列を組み合わせたような形式になっています。深くネストすることも可能ですが、大枠は連想配列になっているのがJSONファイルの特徴です。
Swiftでも利便性の高いJSONファイルを扱うことが可能です。
SwiftでJSONファイルを扱う
SwiftでJSONファイルを扱う上で注意しなければいけないポイントは以下の通りです。
JSONファイルを扱うポイント
- データ型
- エンコード
- デコード
エンコード(encode)とは「符号化」のことで、「一定の規則に準じた形式にデータ変換すること」です。デコード(decode)はその逆で符号化されたデータを元に戻すことをさしています。
今回はエンコードについてまとめていきます。
Swiftの構造体をJSONデータに変換する(エンコード)
Swiftの構造体をJSONデータに変換するためのポイント
- Encodableプロトコル
- JSONEncoderクラス
- JSONが扱える状態(文字コードUTF-8/Data型)へ変換
Encodableプロトコルに準拠した構造体
Swiftの構造体からJSONデータに変換するためには対象の構造体がEncodableプロトコル
に準拠している必要があります。プロトコルはDecodable
プロトコルとEncodable
プロトコルを兼ねたタイプエイリアス(別名)であるCodable
プロトコルを指定しても問題ありません。
struct Person: Encodable {
var name:String
var age:Int
var hobby:String
}
これで構造体の定義が完了したのでJSONに変換したい値を格納しておきます。
let person = Person(name: "Ame", age: 18, hobby: "web制作")
JSONEncoderクラスとは?
エンコードするにはSwiftに標準で定義されている、JSONデータにエンコードするためのJSONEncoder
クラスを使用します。エンコードする際にポイントになるのはoutputFormatting
プロパティとencode
メソッドです。
struct Person: Encodable {
var name:String
var age:Int
var hobby:String
}
let person = Person(name: "Ame", age: 18, hobby: "web制作")
let encoder = JSONEncoder()
// フォーマットを指定
encoder.outputFormatting = .prettyPrinted
// エンコード
let jsonData = try encoder.encode(person)
// 文字コードUTF8のData型に変換
print(String(data: jsonData , encoding: .utf8)!)
問題がなければ下記のようにJSON形式となって出力されます。
{
"name" : "Ame",
"age" : 18,
"hobby" : "web制作"
}
outputFormattingプロパティ
outputFormattingプロパティ
はエンコードしたJSONデータのインデントやサイズ、順序などを指定できるインスタンスプロパティです。設定できる値は下記のものをから選びます。
未指定
未指定の場合はそのまま出力してくれます。
{"name":"Ame\/Tsubaki","age":18,"hobby":"web制作"}
.prettyPrinted
インデントを自動で付与し、読みやすい形で出力してくれるフォーマット値です。
{
"name" : "Ame\/Tsubaki",
"age" : 18,
"hobby" : "web制作"
}
.sortedKeys
キー値を昇順でソートした状態で出力してくれるフォーマット値です。
{"age":18,"hobby":"web制作","name":"Ame\/Tsubaki"}
.withoutEscapingSlashes
「/(スラッシュ)」が入っている場合にエスケープ文字を付けずに出力するフォーマット値です。
{"name":"Ame/Tsubaki","age":18,"hobby":"web制作"}
encodeメソッド
encode
メソッドはJSONEncoder
クラスのジェネリックインスタンスメソッドです。引数に変換したい構造体を渡し、エンコードされたJSONデータが戻り値として帰ってきます。
func encode<T>(_ value: T) throws -> Data where T : Encodable
定義を見るとthrows
句があるので異常があった場合に例外が投げられる可能性があります。encode
メソッドの実行にはtry
文を使用するのを忘れないように注意してください。
ジェネリックと<T>の意味についてはこちらの記事を参考にしてください。
SwiftでJSONとして扱う型式
エンコードが完了した戻り値はSwiftでJSONデータとして扱う型に適さない可能性があります。Swift内でJSON形式のデータであることを認識させるために明示的に適切な変換をおこなっておきます。
ポイント
SwiftでJSONデータを扱うには文字コード:UTF-8のData型にする
適切なData型に変換する方法は幾つかありますが今回はString
のイニシャライザーを使って変換していきます。
// エンコード
let jsonData = try encoder.encode(person)
// 文字コードUTF8のData型に変換
print(String(data: jsonData , encoding: .utf8)!)
引数には変換したいデータとエンコード値を指定します。エンコード値(String.Encoding)はASCII文字やUTF-8など様々な設定値が用意されています。
イニシャライザーの構文
init?(
data: Data,
encoding: String.Encoding
)
ネストされた構造体をJSONデータにエンコードする
構造体の中にさらに構造体が定義されているようなネスト(階層化)されている場合でもエンコードは可能です。
struct School: Encodable {
var schoolName:String
var person:[Person]
}
struct Person: Encodable {
var name:String
var age:Int
var hobby:String
}
let school = School(schoolName:"Webエンジニア学習部屋",person:[Person(name: "Ame", age: 18, hobby: "web制作"), Person(name: "Yoshida", age: 21, hobby: "読書")])
let encoder = JSONEncoder()
// フォーマットを指定
encoder.outputFormatting = .prettyPrinted
// エンコード
let jsonData = try encoder.encode(school)
// 文字コードUTF8のData型に変換
print(String(data: jsonData , encoding: .utf8)!)
構造体から変換されたJSONデータ
{
"person" : [
{
"name" : "Ame",
"age" : 18,
"hobby" : "web制作"
},
{
"name" : "Yoshida",
"age" : 21,
"hobby" : "読書"
}
],
"schoolName" : "Webエンジニア学習部屋"
}
構造体からJSONデータに変換するプロパティを指定する
定義されている構造体のプロパティの中からJSONデータに変換したくないプロパティがある場合は列挙型(enum)CodingKeys
を定義することで変換するプロパティを選択することができます。
例えばhobby
プロパティは変換したくない場合は以下のように定義します。
enum CodingKeysを使った構造体
struct Person: Encodable {
var name:String
var age:Int
var hobby:String
private enum CodingKeys: String, CodingKey {
case name, age
}
}
列挙型(enum)を含んだ構造体を変換する
構造体のプロパティに列挙型(enum)を使用している場合は列挙型にもCodableプロトコルへの準拠が必要になります。指定しない場合はType 'Location' does not conform to protocol 'Encodable'
のようなエラーになります。
struct Location: Codable , Identifiable {
var id = UUID() // 識別子
var address:String // 住所
var name:String // 名称
var memo:String // メモ
var spot:Spot // スポットカテゴリ
}
// 列挙型にもCodableプロトコルへの準拠が必要
enum Spot: String, Codable {
case house // 人の家
case restaurant // 飲食店
case workplace // 仕事場
case shop // ショップ
case facility // 施設
case leisure // レジャー
case nature // 自然
case parking // 駐車場
}
Bool型をJSONに変換時に1や0にする方法
定義したSwiftオブジェクトのプロパティがBool型でもJSONの値をrue/false以外でへ変換させたい場面もあると思います。
詳細はこちらの記事を参考にしてください。
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。