NSDate isEqual 的问题

既然swift开源了,你可以看swift源码里Foundation的相关对象是如何实现的:
apple/swift
简单来说就是一个浮点数比较的问题.

当你获取一个Date对象的timeIntervalSince1970属性时,返回的实际上是self.timeIntervalSinceReferenceDate + Date.timeIntervalBetween1970AndReferenceDate, 其中 Date.timeIntervalBetween1970AndReferenceDate 为常量978307200.0。timeIntervalSinceReferenceDate这个getter方法对应的是内部的_time 存储属性,也就是说timeIntervalSince1970 这个getter方法是通过浮点数加法计算出来的。

然后你用获取到的timeIntervalSince1970这个属性去构造一个新的Date对象,调用的是init(timeIntervalSince1970: TimeInterval) 这个构造函数。这个构造函数内部调用了self.init(timeIntervalSinceReferenceDate: timeIntervalSince1970 - Date.timeIntervalBetween1970AndReferenceDate),也就是说把timeIntervalSince1970 - Date.timeIntervalBetween1970AndReferenceDate 这个浮点数减法表达式的值赋给了新的Date对象的_time属性。

Date是如何实现Comparable使得我们能比较两个Date对象呢?它返回的是lhs.timeIntervalSinceReferenceDate == rhs.timeIntervalSinceReferenceDate,那么其实上就是比较两个Date对象的_time属性。而我们通过上述步骤已经看到,第二个Date对象的_time属性是通过第一个Date对象的_time属性加上一个浮点常量后再减去同一个浮点常量----而这样并不能保证我们一定能得到和原来相同的值。

【NSDate isEqual 的问题】 我们不妨可以做一个实验,在playground里输入如下代码:
let x = 527613976.798304
let y = x + 978307200.0
print(y - 978307200.0 == x)

你可以确认返回的是true还是false : )

那么最后该如何正确的比较两个Date对象是否相等呢?我建议是只要他们的时间间隔的绝对值落在某个范围内就判断相等即可,当然不同的场景可以有不同的方案,这个要靠你自己来判断了。

■网友
建议在category中重写NSDate的对象等同性,即-isEqualsToDate:方法和-isEqual:方法,以及-hash方法,当时间在某个范围之内时即表示相等。这样可以避免浮点运算的问题,想怎么搞就怎么搞。


    推荐阅读