怪現象
Realm iOSを使っているプロジェクトなのですが、怪現象が起きたのをねじ伏せたのでご報告です。
業務系のアプリで、Http越しにJSONを取得してくるAPIが用意されていて、その結果をDictionaryにまず変換する処理があります。
// 通信結果がdataに入っている
let result = try! NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments)
let resultDic = result as! Dictionary
なんのことはない、ふつうです。try!でもみ消しているのはひとまず見なかったことにしてください。
続きまして、その結果がネストした構造になっているので、
let value = resultDic["key1"]!["key2"]["key3"]
のように値を取得することを目論みました。nilに厳しいSwiftでして、密かにアンラップなどしております。ちなみにvalueはJSON文字列なので、String型の想定でその後の処理を書いていました。
そしていざビルドしてみると、謎のエラーが出ました……
確かにプロジェクト内でRealmを使ってはいるのですが、この時点で処理しているのはパースしただけのJSONオブジェクトであり、RLMObjectとは何の関係もありません。また、実際にdynamicTypeで中身の型を確かめてみると、きっちりと文字列になっております。むりやりにas? String?
などしてビルドを通しても、結局該当箇所でクラッシュしてしまいます。
解決策
不可解ですが、ひとまず2つの方法で回避できることがわかりました。
1つ目は、以下のように、毎回キャストすることです。
let key1Dic = resultDic["key1"]! as! Dictionary?
let key2Dic = key1Dic["key2"]! as! Dictionary?
let value = key2Dic["key3"] as! String?
……見るも無残です。
あまりにも醜いその姿を、どうにかして助けてはやれぬものか……
その時私がハッと思い出したのは、イニシエノマホウ、Objective-Cで培ったKey-Value Codingでした。いつもNSDictionaryをパースするのにはあの呪文を唱えていたではないですか……
let loginToken = dic.valueForKeyPath("key1.key2.key3") as! String?
Bravo!!
かくして私は無事にJSONオブジェクト内の文字列を取り出すことに成功したわけであります。
ただし、1点注意があります。上記にも書いていますように、valueForKeyPath
はあくまでNSDictionary
のメソッドであって、Dictionary
のそれではございません。イニシエノマホウですからね。以下のように、最初にJSONをパースする際には、NSDictionaryにキャストしてくださいね。
let result = try! NSJSONSerialization.JSONObjectWithData(data!, options: .AllowFragments)
let resultDic = result as! NSDictionary // NSDictionaryにする
回想録
というかRealm、ときどきこういう挙動があって驚かされます。基本的には好きなんですけど。同じ現象で困っている人のお役に立てれば。もちろん、根本的な原因など、お心当たりの方はご教授いただけると幸いです。読んでいただきありがとうございました。