こんにちは!フリーエンジニアのせきです。
アプリとサーバでデータのやりとりをする時に、JSONという形式がよく使われます。
この記事では、
・JSONとは何か知りたい
・JSON文字列をパースする方法を知りたい
・JSON文字列を作成する方法を知りたい
という基本的な内容から、
・JSONを扱うライブラリについて知りたい
といった応用的な内容に関しても解説していきます。
今回はそんなJSONについて、わかりやすく解説します!
※この記事ではSwift3.1を使用しています。
JSONとは
JSONとはデータの表記法で、Swiftに限らず様々な言語で使用されています。
同様のものにXMLがありますが、より簡潔で可読性のよいものになっています。
JSONはサーバとクライアントでデータをやりとりする際のフォーマットとして広く利用されています。
JSONは「名前: 値」をカンマで区切り、中括弧({})で括って記述します。
「名前: 値」をメンバと呼びます。
メンバの名前は文字列であり、ダブルクォーテーション(”)で囲みます。
メンバの値は以下の表記が可能です。
・文字列値 ダブルクォーテーション(”)で囲みます。
・数値 そのまま記述します。
・真偽値 trueまたはfalseを記述します。
・null値 nullを記述します。
・配列値 カンマ区切りで値を記述し、大括弧([])で囲みます。
・オブジェクト値 「名前: 値」をカンマで区切り、中括弧({})で括る
以下がJSONのサンプルです。
{ "id": 1, "name": "suzuki", "hobby": [ { "name": "sports", "startyear": 2000 }, { "name": "movie", "startyear": 1992 } ] }
「id」の値は数値、「name」の値は文字列値、「hobby」の値はオブジェクト値の配列になっています。
JSONは人が見て分かりやすいよう、インデントやスペースは自由に挿入することができます。
JSON文字列をパースする
サーバから送られてきたJSON文字列をクライアントで使用するには、パース(解析)する必要があります。
JSONSerializationを使用する
ここではApple標準フレームワークのFoundationに含まれているJSONSerializationを使用する方法を解説します。
JSON文字列をパースするには、JSONSerialization.jsonObjectを使用します。
書き方:
JSONSerialization.jsonObject(with JSONデータ: Data, options オプション)
引数:
第一引数にはJSONデータを含むデータオブジェクトを指定します。
第二引数にはオプションを指定します。
戻り値:
JSONデータが入っているFoundationオブジェクトdataが返されます。
以下のJSON文字列をパースするサンプルです。
JSON文字列:
{ "id": 1, "name":"Suzuki" }
サンプルプログラム:
import Foundation // パースするJSON文字列 let jsonString: String = "{\"id\":1, \"name\":\"Suzuki\"}" // JSON文字列をData型に変換 var personalData: Data = jsonString.data(using: String.Encoding.utf8)! do { // パースする let items = try JSONSerialization.jsonObject(with: personalData) as! Dictionary<String, Any> print(items["id"] as! Int) // メンバid Intにキャスト print(items["name"] as! String) // メンバname Stringにキャスト } catch { print(error) }
実行結果:
1 Suzuki
JSONSerializationを使用する場合には、最初に「import Foundation」の宣言が必要になります。
JSON文字列を解析するには、文字列をData型に変換する必要があります。
「jsonString.data(using: String.Encoding.utf8)!」でData型に変換し、その値をJSONSerialization.jsonObjectに渡します。
戻り値にメンバ名を指定し、キャストして値が取得できます。
JSON文字列を作成する
サーバにJSONデータを送るには、JSON文字列を作成する必要があります。
Dictionaryを使用する
JSONのメンバ「名前: 値」はDictionaryで表すことができます。
名前は文字列なのでString固定ですが、値はいろいろな型が考えられるのでAnyで定義することができます。
サンプルプログラム:
var jsonDic = Dictionary<String, Any>() jsonDic["id"] = 1 jsonDic["name"] = "Suzuki" print(jsonDic)
実行結果:
["id": 1, "name": "Suzuki"]
Dictionaryをそのまま表示すると大括弧([])で囲われてしまい、JSON形式ではなくなってしまいます。
JSON形式の文字列にするためには、JSONSerialization.dataを使用します。
書き方:
JSONSerialization.data(withJSONObject JSONデータオブジェクト: Any, options オプション)
引数:
第一引数にはJSONデータが入っているFoundationオブジェクトを指定します。
第二引数にはオプションを指定します。
戻り値:
JSONデータが返されます。
先ほど作成したDictionaryをJSONSerialization.dataに渡し、表示してみます。
サンプルプログラム:
var jsonDic = Dictionary<String, Any>() // キーString、値AnyのDictionary jsonDic["id"] = 1 jsonDic["name"] = "Suzuki" do { // DictionaryをJSONデータに変換 let jsonData = try JSONSerialization.data(withJSONObject: jsonDic) // JSONデータを文字列に変換 let jsonStr = String(bytes: jsonData, encoding: .utf8)! print(jsonStr) } catch (let e) { print(e) }
実行結果:
{"id":1,"name":"Suzuki"}
JSONSerialization.dataの戻り値のJSONデータを「String(bytes: jsonData, encoding: .utf8)!」で文字列に変換しています。
これでJSON形式で表示することができました。
Arrayを使用する
メンバの値の配列値は、Arrayで表すことができます。
サンプルプログラム:
import Foundation var jsonArray = Array<Any>() // 値AnyのArray jsonArray.append(1); jsonArray.append("Suzuki"); do { // ArrayをJSONデータに変換 let jsonData = try JSONSerialization.data(withJSONObject: jsonArray) // JSONデータを文字列に変換 let jsonStr = String(bytes: jsonData, encoding: .utf8)! print(jsonStr) } catch (let e) { print(e) }
実行結果:
[1,"Suzuki"]
ArrayもJSONSerialization.dataを使うことで、JSON形式で表示されます。
階層構造を作成する
以下のような階層構造のJSON文字列を作成してみます。
{ "id":1, "name":"Suzuki", "hobby":[ {"name":"sports","startyear":2000}, {"name":"movie","startyear":1992} ] }
「id」の値は数値、「name」の値は文字列値、「hobby」の値はオブジェクト値の配列になっています。
どんなに複雑なJSONもDictionaryとArrayの組み合わせで記述することができます。
サンプルプログラム:
import Foundation // hobbyひとつめのメンバを作成 var hobby1 = Dictionary<String, Any>() hobby1["name"] = "sports" hobby1["startyear"] = 2000 // hobbyふたつめのメンバを作成 var hobby2 = Dictionary<String, Any>() hobby2["name"] = "movie" hobby2["startyear"] = 1992 // hobbyふたつのメンバをArrayに追加 var hobbyArray = Array<Dictionary<String, Any>>() hobbyArray.append(hobby1) hobbyArray.append(hobby2) var json = Dictionary<String, Any>() json["id"] = 1 // メンバid 値はInt json["name"] = "Suzuki" // メンバname 値はString json["hobby"] = hobbyArray // メンバhobby 値はArray do { // DictionaryをJSONデータに変換 let jsonData = try JSONSerialization.data(withJSONObject: json) // JSONデータを文字列に変換 let jsonStr = String(bytes: jsonData, encoding: .utf8)! print(jsonStr) } catch (let e) { print(e) }
実行結果:
{"name":"Suzuki","id":1,"hobby":[{"name":"sports","startyear":2000},{"name":"movie","startyear":1992}]}
ポイントは下の階層から作成し、それを上の階層に追加していく点です。
先にhobbyの配列の値をDictionaryで作成し、そのDictionaryをArrayに追加していきます。
SwiftyJSONを使ってみる
JSONのメンバの値は様々な型を持つため、パースするにはどのメンバがどの型を持つかを一つ一つ指定しなければならなかったり、nilチェックが必要だったり、面倒な部分もあります。
そんな問題を解決してくれるのが、JSONのための外部ライブラリです。
JSONのための外部ライブラリは、簡単にパースすることができたり、オブジェクトへのマッピングまで行うものもあります。
いくつかあるライブラリの中でもよく使われるのがSwiftyJSONです。
SwiftyJSONを使うと、パース後のJSONオブジェクトが扱いやすくなります。
nilの値にデフォルト値を適用できたり、Arrayに存在しない要素にアクセスしてもクラッシュしないなど、便利な点もあります。
JSONの扱いに慣れたら、ぜひ使ってみてください!
まとめ
今回はJSONについて解説しました。
Swiftに限らず、データのやりとりにはJSONがよく使われますので、ぜひJSONの扱いをマスターしてください。
JSONについて忘れてしまったら、この記事を思い出して下さい!