在Swift中将JSONEncoder用于Equatable方法

时间:2018-10-29 15:55:19

标签: swift codable equatable encodable

我知道JSON密钥没有任何顺序,并且可以随机生成,但是没有什么可以阻止我编写此函数,并且在我的测试中,这不能对我测试的每个用例起作用。

func ==<T: Encodable> (lhs: T, rhs: T) -> Bool {
   let encoder = JSONEncoder()
   do {
       let leftEncoded = try encoder.encode(lhs)
       let rightEncoded = try encoder.encode(rhs)
       return leftEncoded == rightEncoded
   } catch {
       return false
   }
}

我要解决的问题是为一种类型的函数编写一个函数,该类型具有一个协议数组,并具有20种不同的实现方式,我必须实现==函数而不是迅速的自动综合。而且我知道我可以使用选项JSONSerialization.writeJSONObject切换到.sortedKeys来保持按键顺序。

此实现的弊端是什么,而不是其他任何编写==函数的方法?

2 个答案:

答案 0 :(得分:2)

答案似乎在您的问题中:“ JSON密钥没有任何顺序。”同样,在逻辑上相等的两个事物可能会编码不同(例如,如果相等性仅取决于其id)。同样,编码相同值的引用类型可能根本无法等同(例如UIView)。而且,这会产生非常广泛的mkdir .docker重载,这会使类型检查更加昂贵(就像==极其昂贵)。

您正在做的是尝试在可以合成时自动符合+。斯威夫特本可以做到的;实际上,对于大多数Equatable情况,只需添加Encodable就可以合成Equatable。在这种情况下,Swift团队明确选择不自动整合,并在您要表达的意思时强制您请求它,因为它并不总是意味着“所有属性都包含相同的位”。当Swift团队明确选择避免使用某个功能时,重新添加该功能几乎不是一个好主意。

答案 1 :(得分:0)

func ==<T: Codable> (lhs: T, rhs: T) -> Bool {
    let encoder = JSONEncoder()

    guard let lhsData = try? encoder.encode(lhs),
          let rhsData = try? encoder.encode(lhs),
          let left = try? JSONSerialization.jsonObject(with: lhsData) as? [String : Any],
          let right = try? JSONSerialization.jsonObject(with: rhsData) as? [String : Any] else { return false }

    let leftDictionary = left as NSDictionary
    let rightDictionary = right

    return leftDictionary.isEqual(to: rightDictionary)
}