CLLocation如何实现Equatable协议?

5

在回答另一个关于SO的问题时,我发现CLLocation类符合Equatable协议。它使用什么方法来确定相等性?

是纬度/经度的精确匹配吗?纬度/经度和海拔的精确匹配?纬度、经度、海拔和时间戳的精确匹配?速度和航向呢?如果使用只有纬度/经度对的init(latitude:longitude:)创建位置对象,那高度将是多少?该位置的其他各种值都不是可选项,因此我们应该如何处理?


通过继承 NSObject 类?如果您尝试使用两个 CLLocation 对象调用 == 函数,则会发现使用的是为 NSObject 声明的函数:public func ==(lhs: NSObject, rhs: NSObject) -> Bool。比较两个 CLLocation 实例的“正确”方法可能是使用 distance(from:) 并将其与一个 CLLocationDistance 阈值进行比较。 - JAL
1
如果你想知道哪些属性用于确定相等,你应该运行一些具有不同值的测试并观察结果。 - rmaddy
3个回答

2

CLLocation如何实现Equatable协议?

它并没有。没有重写的==函数来比较两个CLLocation实例。当使用两个CLLocation实例调用==时,会使用NSObject==函数:

public func ==(lhs: NSObject, rhs: NSObject) -> Bool

要比较两个CLLocation实例,可以比较每个实例中你关心的属性(如纬度或经度),或者使用内置的distance(from:)方法计算两个位置之间的距离,并将其与CLLocationDistance阈值进行比较。


实际上,distance(from:) 是比较位置的有用方法,其中 == 的默认实现是无用的。一个 distance(from:isWithin:) 可以让您查看两个位置是否在给定距离内(其中 isWithin 以米或千米表示),这将是一个很好的扩展。然而,distance(from:) 可能是一个相当昂贵的函数。我怀疑它在内部使用 Haversine 公式(它可以让您计算球面上两点之间的“大圆”距离)。 - Duncan C
Haversine公式涉及相当多的三角函数计算,这是非常慢的。对于大多数应用程序来说,使用勾股距离的近似值可能已经足够了,而且速度会快得多。你甚至可以创建一个版本,使用勾股距离和粗略的正弦曲线近似来调整结果,以根据距赤道的距离进行修正,从而给出Haversine公式的非常接近的近似值。 - Duncan C
再说了,如果你的计算不是时间关键性的,就不用担心这个问题。只需使用distance(from:)函数即可完成。不要花费时间去优化那些实际上并不影响应用程序运行的代码。(毕竟,“过早优化是万恶之源”) - Duncan C

2

为了完全验证JAL在他的回答中所说的,我写道:

import Foundation
import UIKit
import CoreLocation

class ViewController: UIViewController{

    var cl1 = CLLocation()
    var cl2 = CLLocation()

    override func viewDidLoad() {
        super.viewDidLoad()
        if cl1 == cl2{

        }
    }
}

然后我按住 Command 键并点击 ==(来自 if cl1 == cl2)。它将带我到:

extension NSObject : CVarArg {
}

public func ==(lhs: Selector, rhs: Selector) -> Bool

public func ==(lhs: NSObject, rhs: NSObject) -> Bool

public struct NSZone {
}

为了仔细核对,我进行了命令点击 CLLocation 并看到:

open class CLLocation : NSObject, NSCopying, NSSecureCoding {
...
}

基本上,== 是因为它是从 NSObject 继承的,而 NSObject 只比较引用。

具有误导性的实现。== 映射到 === - Duncan C

0

CLLocation类与任何符合Equatable协议的类一样,实现了(==)运算符

为了回答你的其他问题,我决定使用这段代码启动一个playground

import UIKit
import CoreLocation

var str = "Hello, playground"

var coordinate = CLLocationCoordinate2D.init(latitude: 42.0, longitude: 42.0)
var accuracy = CLLocationAccuracy.init(24.0)
var date = Date.init(timeIntervalSinceNow: 0)

var loc1 = CLLocation.init(coordinate: coordinate, altitude: 44.0, horizontalAccuracy: accuracy, verticalAccuracy: accuracy, timestamp: date)
var loc2 = CLLocation.init(coordinate: coordinate, altitude: 44.0, horizontalAccuracy: accuracy, verticalAccuracy: accuracy, timestamp: date)
var loc3 = CLLocation.init(latitude: 42.0, longitude: 42.0)
var loc4 = CLLocation.init(latitude: 42.0, longitude: 42.0)
var loc5 = CLLocation.init(coordinate: coordinate, altitude: 44.0, horizontalAccuracy: accuracy, verticalAccuracy: accuracy, course: .infinity, speed: 55.0, timestamp: date)
var loc6 = CLLocation.init(coordinate: coordinate, altitude: 44.0, horizontalAccuracy: accuracy, verticalAccuracy: accuracy, course: .infinity, speed: 55.0, timestamp: date)

var bool1 = loc1 == loc2  //false
var bool2 = loc2 == loc3  //false
var bool3 = loc2 == loc2  //true
var bool4 = loc1 == loc4  //false
var bool5 = loc5 == loc6  //false

唯一返回TRUE的bool是bool3。

因此,即使不同CLLocation对象上的各个属性相同,==运算符也不会将对象视为相等。我猜测比较位置的最佳方法是比较您感兴趣的CLLocation对象的字段。


1
你从未将loc3与loc4进行比较! - Duncan C
试用一下吧,但是剧透警告,它是虚假的。 - sfbarry14
"CLLocation类就像任何符合Equatable协议的类一样,实现了(==)运算符。" 嗯,是的,这是公理的。我的意思是它如何进行比较算法? - Duncan C
2
that is as expected - sfbarry14
最可能的情况是 var loc8 = lov7; var bool8 = loc8 == lov7; 是真的。 - sfbarry14
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接