Codable 转换前后比较 JSON 数据
Compare JSON data before and after Codable conversion
我有 Data
对象,其中包含来自服务器的 JSON 响应。
它以这种方式转换为某些 Codable
对象:
let object = try JSONDecoder().decode(Object.self, from: response.data)
出于测试目的,我想将此对象结束编码回 Data
,然后与初始 Data
.
进行比较
let data = try JSONEncoder().encode(object)
第一个假设: 如果 Data
个对象在解码 + 编码后相等,这意味着所有字段都正确地列在我的 Codable
struct
,所有字段都具有有效类型等...转换后我有两个 Data
对象:154362 字节 154435 字节。这意味着它们是不同的。但是当我使用 jsondiff.com 比较它们时,它们似乎 100% 相同。
第二个假设:我尝试将 Data 对象转换为 String,但是 JSON 结构以不同的方式排序......所以这种方式不起作用。
Double
/ Float
值存在一些问题。它们在解码期间以这种方式解释:41.01 结果为 41.009999999.
所以问题是:有没有办法验证两个 JSON 对象在解码 + 编码前后是否相同?
当前解决方案: 我决定尝试 JSONSerialization
因为自 iOS 11 以来它有一个很好的写作选项:
@available(iOS 11.0, *)
public static var sortedKeys: JSONSerialization.WritingOptions { get }
通过这种方式,我将 Data
转换为正确排序的 json:
@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
}
}
比较两个 json Data
对象是否可靠?
我创建了一个小的 iOS11 Data
扩展,它帮助我比较 JSON 对象并找到任意两个对象的第一行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()
}
}
}
}
我有 Data
对象,其中包含来自服务器的 JSON 响应。
它以这种方式转换为某些 Codable
对象:
let object = try JSONDecoder().decode(Object.self, from: response.data)
出于测试目的,我想将此对象结束编码回 Data
,然后与初始 Data
.
let data = try JSONEncoder().encode(object)
第一个假设: 如果 Data
个对象在解码 + 编码后相等,这意味着所有字段都正确地列在我的 Codable
struct
,所有字段都具有有效类型等...转换后我有两个 Data
对象:154362 字节 154435 字节。这意味着它们是不同的。但是当我使用 jsondiff.com 比较它们时,它们似乎 100% 相同。
第二个假设:我尝试将 Data 对象转换为 String,但是 JSON 结构以不同的方式排序......所以这种方式不起作用。
Double
/ Float
值存在一些问题。它们在解码期间以这种方式解释:41.01 结果为 41.009999999.
所以问题是:有没有办法验证两个 JSON 对象在解码 + 编码前后是否相同?
当前解决方案: 我决定尝试 JSONSerialization
因为自 iOS 11 以来它有一个很好的写作选项:
@available(iOS 11.0, *)
public static var sortedKeys: JSONSerialization.WritingOptions { get }
通过这种方式,我将 Data
转换为正确排序的 json:
@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
}
}
比较两个 json Data
对象是否可靠?
我创建了一个小的 iOS11 Data
扩展,它帮助我比较 JSON 对象并找到任意两个对象的第一行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()
}
}
}
}