【问题标题】:Apparently, CLLocation objects cannot be archived / unarchived precisely显然,CLLocation 对象无法精确归档/取消归档
【发布时间】:2018-01-19 14:38:22
【问题描述】:

在我的应用程序中(仅显示相关代码),我有一个带有属性的类 Test

var location: CLLocation  

我使用

归档它
public func encode(with aCoder: NSCoder) {
    aCoder.encode(location, forKey: "location")
}  

使用

取消归档
required convenience public init?(coder aDecoder: NSCoder) {
    let unarchivedLocation = aDecoder.decodeObject(forKey: "location") as! CLLocation
    self.init(location: unarchivedLocation)
}  

单元测试使用

func test_archiningUnarchiving() {
    // given
    let location = CLLocation.init(latitude: 0.0, longitude: 0.0)
    let test = Test(location: location)
    // when
    let data = NSKeyedArchiver.archivedData(withRootObject: test)
    let unarchivedTest = NSKeyedUnarchiver.unarchiveObject(with: data) as? Test
    // then
    XCTAssertEqual(unarchivedTest!.location, location, "location was not correctly unarchived")
}  

此测试失败:

XCTAssertEqual failed: ("<+0.00000000,+0.00000000> +/- 0.00m (speed -1.00 mps / course -1.00) @ 1/19/18, 3:30:50 PM Central European Standard Time") is not equal to ("<+0.00000000,+0.00000000> +/- 0.00m (speed -1.00 mps / course -1.00) @ 1/19/18, 3:30:50 PM Central European Standard Time") - location was not correctly unarchived

对于原始位置和未存档位置,日志显示了两次完全相同的数据。
知道可能出了什么问题吗??

【问题讨论】:

  • 我认为您在测试中将 CLLocation 与 ShoppingLocation 进行比较是不正确的吗?
  • 哦,对不起,我简化了代码,忘记编辑了。我将编辑我的问题,感谢您指出这一点!
  • 试试let x = CLLocation(); let y = x.copy() as! CLLocation; XCTAssertEqual(x, y);。那也失败了。这可能是比编码更基本的问题。我打赌它会退回到 NSObject isEqual 方法,只有当它们指向同一个实例时才会返回 true。
  • @Rob 你认为我应该提交错误报告吗?
  • 他们可能会忽略“错误”报告,因为它似乎按记录工作。但也许是一个“增强”请求......

标签: ios unit-testing cllocation nskeyedarchiver nskeyedunarchiver


【解决方案1】:

问题不在于归档,而在于相等性测试。如果您比较两个不同的CLLocation 实例,即使它们相同,它也将始终返回false

归根结底,任何未显式实现 isEqual:NSObject 子类(例如 CLLocation 的情况)都会遇到此行为。

Using Swift with Cocoa and Objective-C: Interacting with Objective-C APIs 说:

Swift 提供===== 运算符的默认实现,并为派生自NSObject 类的对象采用Equatable 协议。 == 运算符的默认实现调用 isEqual: 方法...您不应覆盖从 Objective-C 导入的类型的相等或标识运算符。

而且,Concepts in Objective-C Programming: Introspection 告诉我们:

isEqual: 的默认 NSObject 实现只检查指针是否相等。

就个人而言,我希望NSObject 子类不会自动继承isEqual:,但它就是这样。

底线,除非您知道它已正确实现 isEqual: 覆盖,否则不要尝试测试 NSObject 子类的相等性。如果需要,请编写自己的方法,例如isEqual(to location: CLLocation)(但不是 isEqual(_:))执行两个 CLLocation 对象的成员比较。

【讨论】:

  • 谢谢,Rob,我不知道这一点!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多