UserDefaultsに辞書型を突っ込んだ際に、こんなエラーになりました。
Attempt to set a non-property-list object
このときは突っ込んだのが辞書型で、KeyにInt型、Valueに配列が入ったちょっと複雑なやつだったので、
配列がHashableじゃなかったからダメなのかな〜と思って(←誤解)、
突っ込もうとしていたデータを分割して、
Keyだけの配列、Valueだけの配列をそれぞれUserDefaultsに突っ込んで、配列のindexで紐付けようかと思ったんですが、
これでもできなくはないんですが、バグがあったときに収集つかなくなるなと思い、ちゃんと原因を調べました。
辞書型のKeyにできる値
まず僕が最初にした誤解について。
@frozen struct Dictionary where Key : Hashable
辞書型のKeyはHashableである必要があります。
ただValueに関しては自由なので、配列でも辞書型でも突っ込めます。
Hashableに準拠しているかどうかは、公式ドキュメントかXcodeで定義を参照するかするとわかりますが、
IntやStringなど標準的な型はHashableです。
ただ、ArrayやDictionaryはHashableには準拠していないので、Keyにはできません。
※公式ドキュメント見ると、Conforms Toの中にHashableがあるので、一瞬準拠しているように見えるのですが、「Conforms when Value conforms to Hashable.」と注意書きがあります。
property-listとは?
どうやらエラーの原因は辞書型のエラーというよりは、UserDefaultsのエラーっぽいぞ? と気づきました。
僕が打ち込もうとしていた型は、KeyをInt型にしていたので、Hashableはクリアしています。
というかそもそもエラー文はそんなこと言っていない。。。
エラーに真面目に向き合ってみると、Property Listsに入っていないことが問題っぽいですが……?
この一覧を見る限り、Dictionaryも使えるはずで、NSDictionaryにキャストするといけるのかな? とか試してみたんですが、結果は変わらず。
ところが、
And although NSDictionary and CFDictionary objects allow their keys to be objects of any type, if the keys are not string objects, the collections are not property-list objects
ん?
if the keys are not string objects, the collections are not property-list objects
えーっ!
というわけで、KeyをInt型→String型にキャストしたら解決しました。
StringにキャストできないKeyを使いたい方は、一度Data型(JSON Decodeを使うといいみたい)にすると突っ込めるらしいです。