为何CLLocation遵循Equatable协议但CLLocationCoordinate2D却不遵循?坐标比较实现的困惑求助
为何CLLocation遵循Equatable协议但CLLocationCoordinate2D却不遵循?坐标比较实现的困惑求助
这个问题我之前也纠结过,确实有点反直觉!先帮你理清楚背后的设计逻辑,再给你靠谱的解决方案:
一、为啥Apple要这么设计?
其实核心是两个类型的定位和使用场景完全不同:
- CLLocation是一个完整的「位置快照」,它不仅包含坐标,还带了时间戳、海拔、定位精度这些元数据。Apple给它实现Equatable,是为了让开发者判断「两个完整的位置记录是否完全一致」——毕竟在很多场景下,你需要确认两次定位返回的是不是同一个完整的位置数据(包括时间点)。
- 而CLLocationCoordinate2D只是一个纯坐标结构体,这里的坑在于:它的latitude和longitude都是Double类型的浮点数!直接用
==比较浮点数本身就有精度陷阱——比如定位返回的坐标可能因为设备误差有细微的数值差异,明明是同一个地点,用严格的数值相等会返回false。Apple可能是不想默认提供一个容易踩坑的实现,而是把「什么样的坐标算相等」的判断权交给开发者,毕竟不同场景的精度需求不一样:有的要精确到米,有的要精确到厘米,有的甚至只需要精确到城市级别。
二、你之前的方法为啥不行?
你想用CLLocation间接比较坐标的思路是对的,但问题出在CLLocation的Equatable实现会比较所有属性——包括默认生成的timestamp!每次初始化CLLocation时,如果你不手动指定timestamp,它会默认设为当前时间,所以哪怕坐标完全一样,两个CLLocation实例的时间戳也大概率不同,导致==返回false,这显然不是你要的效果。而且硬改CLLocation的逻辑也确实没必要,反而会把问题复杂化。
三、正确的坐标比较实现
我们可以自己给CLLocationCoordinate2D扩展Equatable,根据自己的场景选择合适的精度:
场景1:大多数业务场景(允许微小精度误差)
比如精确到小数点后6位(对应地球上约1米的误差,完全满足绝大多数定位相关的业务需求):
extension CLLocationCoordinate2D: Equatable { public static func == (lhs: Self, rhs: Self) -> Bool { // 用绝对值差判断是否在精度范围内 let latitudeMatch = abs(lhs.latitude - rhs.latitude) < 1e-6 let longitudeMatch = abs(lhs.longitude - rhs.longitude) < 1e-6 return latitudeMatch && longitudeMatch } }
之后你就可以直接用==比较坐标了:
let here = CLLocationCoordinate2D(latitude: 0, longitude: 0) let there = CLLocationCoordinate2D(latitude: 0, longitude: 0) if here == there { print("坐标一致") } else { print("坐标不一致") }
场景2:严格数值相等(比如测试用例)
如果是在测试用例里比较硬编码的坐标,不需要考虑精度问题,可以用严格的数值相等:
extension CLLocationCoordinate2D: Equatable { public static func == (lhs: Self, rhs: Self) -> Bool { return lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude } }
总结
Apple的这个设计选择其实是合理的:CLLocation的Equatable服务于完整位置记录的比较,而CLLocationCoordinate2D的比较场景太灵活,所以把控制权交给开发者。自己扩展Equatable是最直接、最可控的解决方案,比折腾CLLocation靠谱多了。
内容来源于stack exchange
相关产品推荐
相关产品推荐

