显然,CLLocation 对象不能精确地归档/取消归档
Apparently, CLLocation objects cannot be archived / unarchived precisely
在我的应用程序中(仅显示相关代码),我有一个 class 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
实例,即使它们是相同的,它也总是 return false
.
最重要的是,任何未明确实现 isEqual:
的 NSObject
子类(例如 CLLocation
的情况)都会遇到此行为。
Using Swift with Cocoa and Objective-C: Interacting with Objective-C APIs 说:
Swift provides default implementations of the ==
and ===
operators and adopts the Equatable
protocol for objects that derive from the NSObject
class. The default implementation of the ==
operator invokes the isEqual:
method ... You should not override the equality or identity operators for types imported from Objective-C.
而且,Concepts in Objective-C Programming: Introspection 告诉我们:
The default NSObject
implementation of isEqual:
simply checks for pointer equality.
就个人而言,我希望 NSObject
子类不会自动继承 isEqual:
,但事实就是如此。
底线,不要尝试测试 NSObject
子类的相等性,除非您知道它已正确实现 isEqual:
覆盖。如果你愿意,写你自己的方法,例如isEqual(to location: CLLocation)
(但不是 isEqual(_:)
)执行两个 CLLocation
对象的成员比较。
在我的应用程序中(仅显示相关代码),我有一个 class 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
实例,即使它们是相同的,它也总是 return false
.
最重要的是,任何未明确实现 isEqual:
的 NSObject
子类(例如 CLLocation
的情况)都会遇到此行为。
Using Swift with Cocoa and Objective-C: Interacting with Objective-C APIs 说:
Swift provides default implementations of the
==
and===
operators and adopts theEquatable
protocol for objects that derive from theNSObject
class. The default implementation of the==
operator invokes theisEqual:
method ... You should not override the equality or identity operators for types imported from Objective-C.
而且,Concepts in Objective-C Programming: Introspection 告诉我们:
The default
NSObject
implementation ofisEqual:
simply checks for pointer equality.
就个人而言,我希望 NSObject
子类不会自动继承 isEqual:
,但事实就是如此。
底线,不要尝试测试 NSObject
子类的相等性,除非您知道它已正确实现 isEqual:
覆盖。如果你愿意,写你自己的方法,例如isEqual(to location: CLLocation)
(但不是 isEqual(_:)
)执行两个 CLLocation
对象的成员比较。