SwiftでのJSONの簡単な作業

一見すると、SwiftでJSON形式を操作するのに特別な問題はありません。一方で、標準セットにはファイルを解析できるNSJSONSerializationクラスがあります。 この記事のフレームワークでは、JSONファイルをより速く読み取る方法と、明らかなアプローチの動作が遅い理由を検討したいと思います。



そのため、最初に解決する問題を定式化する必要があります。次の構造のかなり大量のJSON(約30メガバイト)があります。



データ-> [ノード]-> [アイテム]-> id:文字列、pos:[Int]、coo:[Double]



文字列フィールドIDを持ち、posフィールドは整数配列、cooフィールドは浮動小数点数の配列である、それぞれItem型のオブジェクトの配列を解析および取得する必要があります。



オプション1-サードパーティライブラリを使用:



私が得たすべてのソリューションはパーサーとして標準のNSJSONSerializationを使用し、それらのタスクは「構文糖」とより厳密なタイピングを追加することだけに見られたと言わなければなりません。 例として、最も人気のあるSwiftyJSONの1つを取り上げます。



let json = JSON(data: data) if let nodes = json["data"].array { for node in nodes { if let items = node.array { for item in items { if let id = item["id"].string, let pos = item["pos"].arrayObject as? [Int], let coo = item["coo"].arrayObject as? [Double] { Item(id: id, pos: pos, coo: coo) } } } } }
      
      





iPhone 6では、このコードの実行に約7.5秒かかりました。これは、非常に高速なデバイスでは禁止されています。

さらに比較するために、今回を参考として検討します。

次に、SwiftyJSONを使用せずに同じものを書き込もうとします。



オプション2は、クリーンスイフトの使用です。



 let json = try! NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) if let nodes = (json as? [String: AnyObject])?["data"] as? [[[String: AnyObject]]] { for node in nodes { for item in node { if let id = item["id"] as? String, let pos = item["pos"] as? [Int], let coo = item["coo"] as? [Double] { Item(id: id, pos: pos, coo: coo) } } } }
      
      





私たちの「バイク」は6秒(オリジナルの80%)で完了しましたが、それでも非常に長い時間を要しました。



プロファイラは次の行を提案します:



 let nodes = (json as? [String: AnyObject])?["data"] as? [[[String: AnyObject]]]
      
      





予想外に長く実行されました。



SwiftのNSJSONSerializationクラスの動作は、Objective-Cの動作に完全に類似しています。つまり、解析の結果は、NSDictionary、NSArray、NSNumber、NSString、NSNullなどのオブジェクトで構成される階層になります。 同じコマンドは、これらのクラスのオブジェクトをSwiftの配列および辞書構造に変換します。つまり、データをコピーします。 (Swiftの配列は、Objective-CよりもC ++の配列に似ています)



そのようなコピーを避けるには、美しいSwift'a型付き配列を使用しないようにしてください。



オプション3-配列と辞書を使用しない場合:



 let json = try! NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) if let nodes = (json as? NSDictionary)?["data"] as? NSArray { for node in nodes { if let node = node as? NSArray { for item in node { if let item = item as? NSDictionary, let id = item["id"] as? NSString, let pos = item["pos"] as? NSArray, let coo = item["coo"] as? NSArray { var _pos = [Int](count: pos.count, repeatedValue: 0) var _coo = [Double](count: coo.count, repeatedValue: 0) for var i = 0; i < pos.count; i++ { if let p = pos[i] as? NSNumber { _pos.append(p.integerValue) } } for var i = 0; i < coo.count; i++ { if let c = coo[i] as? NSNumber { _coo.append(c.doubleValue) } } Item(id: String(id), pos: _pos, coo: _coo) } } } } }
      
      





もちろん、ひどく見えます。 しかし、私たちは主に速度に関心があります:2秒(SwiftyJSONよりもほぼ4倍速い!)



したがって、暗黙的な変換を排除すると、速度が大幅に向上します。




All Articles