概要
SwiftのDictionaryは順番が保証されないですが、それでトラブったので調べたことを書きます。
事の発端
Xcodeをアップデートした後にiOS側で生成したJSON文字列の並びが毎回違うことが発覚。
その後調査したところアプリの起動毎にDictionary型のデータの並び順が変わっていたのでJSONのデータの並び順が変わっていた事がわかりました。
何が起こってたのか?
Dictionary生成時に記載した順番と生成されたデータの順番が変わってました。
以前は順番が変わらなかったのですが、
ランタイムで生成されたDictionaryの順番が変わるみたいです。
いつ頃から起こってたか?
おそらくXcode9.4あたり...?
コマンドラインツールなど環境が根本原因なのか古いXcodeを入れ直しても再現できませんでした。
恥ずかしながらXcodeのアップデートを怠っていたのでXcode10で発覚。
Xcode9.3だと問題が発覚しなかったのと、古い別のMacに残ってたXcode9.4.1で検証しても起きてたのでこのあたりが怪しそうです。
ただDictionaryで順番担保しないのは知ってたので、これはコードを書いた側のミスですね...
環境再現ができなかったのでわからずじまいですが、型推論で別の型になってたりなんてのもありえるのかもしれません。
Dictionaryおさらい
Dictionaryは変更を加える際には順番は保証できるけどそれ以外はできない
とのこと。
たぶんremoveとかのmutationでは順番は変更されないとかですかね。
The order of key-value pairs in a dictionary is stable between mutations but is otherwise unpredictable.
Dictionary - Swift Standard Library | Apple Developer Documentation
解決策
JSONの生成時に順番が保証されてればいい場合
JSONSerialization.WritingOptions
のsortedKeys
を使いましょう。
key順番でソートしてくれます。
sortedKeys - JSONSerialization.WritingOptions | Apple Developer Documentation
ただiOS11からなのでiOS10は爆発するしかない。
Dictionaryで順番も担保したい場合
順番を担保したいなら実行速度が遅いけどDictionaryLiteralってのがあるよ
だそうです。
If you need an ordered collection of key-value pairs and don’t need the fast key lookup that Dictionary provides, see the DictionaryLiteral type for an alternative.
DictionaryLiteral - Swift Standard Library | Apple Developer Documentation
使ってみたところkey-valueのtupleをArrayにしたみたいな感じで使い勝手が悪いので役に立たなそう。
当然ながらJSONにできないです。
使い所が思い浮かばないのでうまい使い方があるのか知りたいです。
まとめ
- ドキュメントはちゃんと読んでから開発しましょう
- JSONの文字列生成時にはオプションでsortedKeysをつけると順番を固定できます