はじめに
UnityでJSONデータをシリアライズ、でシリアライズといった操作をする時に、どうやって実装されていますか?
Unityには標準でJSONデータを操作するための機能があります。
それがJsonUtilityです。
今回はこのJsonUtilityについてご紹介します。
公式ドキュメントはこちらです。
UnityEngine.JsonUtility - Unity スクリプトリファレンス
まずは各メソッドについて説明します。
ToJson
public static string ToJson (object obj);
オブジェクトをJsonフォーマットの文字列へと変換します。
※publicフィールド、もしくはSerializeField Attributeが指定されたオブジェクトが変換対象となります。
FromJson
public static T FromJson<T> (string json);
Jsonフォーマットの文字列からT型のオブジェクトを生成します。
FromJsonOverwrite
public static void FromJsonOverwrite (string json, object objectToOverwrite);
json引数にJsonフォーマットの文字列を渡し、それをobjectToOverwrite引数に設定したオブジェクトに対して上書きする。
実行速度を計測してみる
以下のようなスクリプトを追加して、実行速度を計測してみました。
stringのリスト
まずはstringのリストのフィールドをもったクラスで試してみます。
Serializableなし
using System.Collections.Generic; using UnityEngine; using System.Diagnostics; public class JsonUtilityTest : MonoBehaviour { void Start() { var data = new Data(); for (var i = 0; i < 100000; ++i) { data.list.Add("testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest"); } var stopwatch = Stopwatch.StartNew(); stopwatch.Start(); var json = JsonUtility.ToJson(data); stopwatch.Stop(); UnityEngine.Debug.Log("---------ToJson-----------"); UnityEngine.Debug.LogFormat("Elapsed: {0} ms", stopwatch.ElapsedMilliseconds); UnityEngine.Debug.LogFormat("json length:{0}", json.Length); stopwatch.Restart(); var data2 = JsonUtility.FromJson<Data>(json); stopwatch.Stop(); UnityEngine.Debug.Log("---------FromJson-----------"); UnityEngine.Debug.LogFormat("Elapsed: {0} ms", stopwatch.ElapsedMilliseconds); stopwatch.Restart(); var data3 = new Data(); JsonUtility.FromJsonOverwrite(json, data3); stopwatch.Stop(); UnityEngine.Debug.Log("---------FromJsonOverwrite-----------"); UnityEngine.Debug.LogFormat("Elapsed: {0} ms", stopwatch.ElapsedMilliseconds); } } public class Data { public List<string> list = new List<string>(); }
これを実行すると以下のようになりました。
Serializableあり
次に、Dataクラスに以下のようにSerializable Attributeを指定してみます。
[System.Serializable] public class Data { public List<string> list = new List<string>(); }
結果はこんな感じになりました。
FromJson使うならSerializableつけた方がいいけど、FromJsonOverwite使う場合は不要そう。
boolのリスト
stringのリストで検証したので、次はboolのリストで検証してみました。
using System.Collections.Generic; using UnityEngine; using System.Diagnostics; public class JsonUtilityTest : MonoBehaviour { // Start is called before the first frame update void Start() { var data = new Data(); for (var i = 0; i < 10000000; ++i) { data.list.Add(true); } var stopwatch = Stopwatch.StartNew(); stopwatch.Start(); var json = JsonUtility.ToJson(data); stopwatch.Stop(); UnityEngine.Debug.Log("---------ToJson-----------"); UnityEngine.Debug.LogFormat("Elapsed: {0} ms", stopwatch.ElapsedMilliseconds); UnityEngine.Debug.LogFormat("json length:{0}", json.Length); stopwatch.Restart(); var data2 = JsonUtility.FromJson<Data>(json); stopwatch.Stop(); UnityEngine.Debug.Log("---------FromJson-----------"); UnityEngine.Debug.LogFormat("Elapsed: {0} ms", stopwatch.ElapsedMilliseconds); stopwatch.Restart(); var data3 = new Data(); JsonUtility.FromJsonOverwrite(json, data3); stopwatch.Stop(); UnityEngine.Debug.Log("---------FromJsonOverwrite-----------"); UnityEngine.Debug.LogFormat("Elapsed: {0} ms", stopwatch.ElapsedMilliseconds); } } public class Data { public List<bool> list = new List<bool>(); }
今回もDataクラスにSerializableをつけたものと、つけていないもので比較してみました。
Serializableなし
Serializableあり
やはり、結果は同じようにSerializableをつけるならFromJsonを使った方がよさそうですね
Listをそのまま渡してみる
以下のようにクラスを定義せず、リストをそのまま渡してみます。
using System.Collections.Generic; using UnityEngine; using System.Diagnostics; public class JsonUtilityTest : MonoBehaviour { // Start is called before the first frame update void Start() { var data = new List<string>(); for (var i = 0; i < 100000; ++i) { data.Add("testtesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttesttest"); } var stopwatch = Stopwatch.StartNew(); stopwatch.Start(); var json = JsonUtility.ToJson(data); stopwatch.Stop(); UnityEngine.Debug.Log("---------ToJson-----------"); UnityEngine.Debug.LogFormat("Elapsed: {0} ms", stopwatch.ElapsedMilliseconds); UnityEngine.Debug.LogFormat("json length:{0}", json.Length); UnityEngine.Debug.Log("json:" + json); stopwatch.Restart(); var data2 = new List<string>(); JsonUtility.FromJsonOverwrite(json, data2); stopwatch.Stop(); UnityEngine.Debug.Log("---------FromJsonOverwrite-----------"); UnityEngine.Debug.LogFormat("Elapsed: {0} ms", stopwatch.ElapsedMilliseconds); UnityEngine.Debug.Log("length:" + deserializedData.Count); } }
すると、以下のようにjsonが正しく生成されていないのがわかります。
JsonUtilityを使う場合はクラスを定義する必要があります。
最後に
今回はJsonUtilityについてご紹介しました。
Jsonからオブジェクトを生成する方法は二通りありましたが、
再利用したり、上書きしたりすることがあるならFromJsonOverwrite、
それ以外はFromJsonを使うといった使い分けをするのがよさそうですね。