How does CLLocation implement the Equatable protocol?

1.7k views Asked by At

In answering another question on SO, I found that the CLLocation class conforms to the Equatable protocol. What method does it use to determine equality?

Exact match of lat/long? Exact match of lat/long and altitude? Exact match of latitude, longitude, altitude, and timestamp? What about speed and course? What about CLLocation objects that were created with only a lat/long pair? Various other values of the location are not optionals, so what would the altitude be for a location created using init(latitude:longitude:)?

3

There are 3 answers

1
mfaani On BEST ANSWER

Just fully verify what JAL has said in his answer, I wrote:

import Foundation
import UIKit
import CoreLocation

class ViewController: UIViewController{

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

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

        }
    }
}

Then I command clicked on the == (from if cl1 == cl2). It took me to:

extension NSObject : CVarArg {
}

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

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

public struct NSZone {
}

To double check I command clicked on CLLocation and saw:

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

So basically the == is because it's subclassed from NSObject which only compares references.

11
sfbarry14 On

CLLocation class much like any class that conforms to Equatable, implements the (==) operator

And to answer your other questions I decided to start up a playground with this code

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

and the only bool that yields TRUE is bool3.

so regardless if the individual properties on different CLLocation objects are the same the == operator will not see the objects as equal. Im guessing the best way to for one to compare locations is to compare the fields off the CLLocation objects that are of interest to you

3
JAL On

How does CLLocation implement the Equatable protocol?

It doesn't. There is no overridden == function which compares two CLLocation instances. When calling == with two CLLocation instances, the NSObject == function is used:

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

To actually compare two CLLocation instances, either compare the properties on each you care about (latitude or longitude), or use the built in distance(from:) method with two locations and compare that to a CLLocationDistance threshold.