2017-10-26 9 views
0

サーバーからのJSON応答を含むDataオブジェクトがあります。私は戻ってDataにこのオブジェクトをENDCODE、その後Data初期と比較したいテストの目的のためにコーディング可能な前後のJSONデータの比較

let object = try JSONDecoder().decode(Object.self, from: response.data) 

は、それはいくつかのCodableオブジェクトこのように変換されます。

let data = try JSONEncoder().encode(object) 

第一の仮定:Dataオブジェクトがデコード+エンコード後に同じであれば、それはすべてのフィールドが正しく私のCodablestructに記載されていることを意味し、すべてのフィールドが有効なタイプとなどを持っている...変換した後、私は」 2つのDataオブジェクトがあります:154362バイト154435バイト。それは彼らが異なっていることを意味します。しかし、私がjsondiff.comを使ってそれらを比較すると、彼らは100%同一であるようです。

第2の仮定:データオブジェクトをStringに変換しようとしましたが、JSON構造体が別の方法でソートされました。このようには動作しません。

Double/Floatの値にはいくつか問題があります。これらは復号化中にこのように解釈されます。41.01の結果は41.009999999になります。

質問:2つのJSONオブジェクトがデコード+エンコードの前後で同一であることを検証する方法はありますか?

現在のソリューション:

@available(iOS 11.0, *) 
public static var sortedKeys: JSONSerialization.WritingOptions { get } 

私は適切にソートされたJSONにDataを変換するこの方法は: iOSの11以来、それは偉大な書き込みオプションを持っているので、私はJSONSerializationを試してみることにしまし

@available(iOS 11, *) 
private extension Data { 

    static func equal(json1: Data, json2: Data) -> Bool { 
     return json1.serialized == json2.serialized 
    } 

    var serialized: Data? { 
     guard let json = try? JSONSerialization.jsonObject(with: self) else { 
      return nil 
     } 
     guard let data = try? JSONSerialization.data(withJSONObject: json, options: [.sortedKeys, .prettyPrinted]) else { 
      return nil 
     } 
     return data 
    } 
} 

2つのjson Dataオブジェクトを比較する信頼性の高い方法ですか?

+0

「JSONEncoder/Decoder」は非常に制限的です。矛盾が発生するとエラーになります。操作が成功すると、データが正しく処理されたことを確認できます。入力/出力差は、浮動小数点値が関与する場合にのみ発生します。浮動小数点値の精度を制御する必要がある場合は、 'NumberFormatter'を使用してください。 – vadian

+0

構造体にフィールドがなくても初期のjsonに存在する場合、エラーはスローされません – iWheelBuy

答えて

1

iOS11Dataという拡張子を作成しました。この拡張子を使用すると、JSONオブジェクトを比較して、2つのJSONオブジェクトが不一致している最初の行を見つけることができます。

@available(iOS 11, *) 
public extension Data { 

    public func jsonSerialized() -> Data? { 
     guard let json = try? JSONSerialization.jsonObject(with: self) else { 
      return nil 
     } 
     let object: Any = { 
      if let array = json as? Array<Any> { 
       return array.strippingNulls() 
      } else if let dictionary = json as? Dictionary<String, Any> { 
       return dictionary.strippingNulls() 
      } else { 
       return json 
      } 
     }() 
     guard let data = try? JSONSerialization.data(withJSONObject: object, options: [.sortedKeys, .prettyPrinted]) else { 
      return nil 
     } 
     return data 
    } 

    public static func jsonMismatch(lhs: Data, rhs: Data, alreadySerialized: Bool = false) -> Int? { 
     switch alreadySerialized { 
     case true: 
      return _jsonMismatch(lhs: lhs, rhs: rhs) 
     case false: 
      guard let lhs = lhs.jsonSerialized(), let rhs = rhs.jsonSerialized() else { 
       return nil 
      } 
      return _jsonMismatch(lhs: lhs, rhs: rhs) 
     } 
    } 

    private static func _jsonMismatch(lhs: Data, rhs: Data) -> Int? { 
     guard let string1 = String(data: lhs, encoding: .utf8), let string2 = String(data: rhs, encoding: .utf8) else { 
      return nil 
     } 
     let components1 = string1.components(separatedBy: "\n") 
     let components2 = string2.components(separatedBy: "\n") 
     let count = components1.count < components2.count ? components1.count : components2.count 
     for index in 0 ..< count { 
      if components1[index] != components2[index] { 
       return index 
      } 
     } 
     return nil 
    } 
} 

private extension Array where Element == Any { 

    func strippingNulls() -> Array { 
     var array = self 
     array.stripNulls() 
     return array 
    } 

    mutating func stripNulls() { 
     let count = self.count 
     guard count > 0 else { 
      return 
     } 
     for _index in 0 ..< count { 
      let index = count - 1 - _index 
      if self[index] is NSNull { 
       remove(at: index) 
      } else if let array = self[index] as? [Any] { 
       self[index] = array.strippingNulls() 
      } else if let dictionary = self[index] as? [String: Any] { 
       self[index] = dictionary.strippingNulls() 
      } 
     } 
    } 
} 

private extension Dictionary where Key == String, Value == Any { 

    func strippingNulls() -> Dictionary { 
     var dictionary = self 
     dictionary.stripNulls() 
     return dictionary 
    } 

    mutating func stripNulls() { 
     for (key, value) in self { 
      if value is NSNull { 
       removeValue(forKey: key) 
      } else if let array = value as? [Any] { 
       self[key] = array.strippingNulls() 
      } else if let dictionary = value as? [String: Any] { 
       self[key] = dictionary.strippingNulls() 
      } 
     } 
    } 
} 
関連する問題