The overload of the "<" operator declared in the Swift class is sometimes not called when used in Objective-C

I ran into a weird Swift / Objective-C compatibility issue. The point is this:

I have @objc public class GKDistance:NSObject,NSCoding,Comparable , written in Swift. To compare distances, I added operator overloading for < as follows:

 public func <(a:GKDistance, b:GKDistance) -> Bool { return a.value < b.value } public func ==(a:GKDistance, b:GKDistance) -> Bool { return a.value == b.value } 

Then it is used in the Objective-C method, for example:

 if (distance < averageDistance){ // code } 

When the Objective-C method is called, I can add a print() statement and a breakpoint in the < method to confirm when the operator overload is used. In one case, it mysteriously skips the operator overload defined in Swift and uses the usual Objective-C comparator between two GKDistance objects.

When launched with distance.value == 2375.1842554877021 and averageDistance.value == 75.671794891357421 , distance < averageDistance returns true , the Swift statement is never overloaded, and Objective-C executes the code inside the conditional expression.

If I convert the Objective-C method to Swift, it will behave as expected, but I am worried that there are other GKDistance comparisons in various Objective-C methods in our application that may not see the Swift overload operator.

Does anyone encounter similar Swift / Objective-C compatibility issues as it relates to operator overloading?

+5
source share
1 answer

Your

 public func <(a:GKDistance, b:GKDistance) -> Bool { } 

- like all Swift operators - the top-level function and top-level functions are not exported to Objective-C, see "Swift Type Compatibility" in Interaction with the Objective-C API .

Also note that you cannot override operators (e.g. < ) in (Objective-) C, see for example

Therefore in

 if (distance < averageDistance) { // code } 

only two pointers are compared, and the condition is true if the object pointed to by distance is in the lower memory address than the pointer to the averageDistance object (which is obviously not what you intended).

What you can do is implement the compare: method in your class, similar to NSString or NSNumber .

Note that for NSObject subclasses you must override isEqual: instead of == , compare

+2
source

All Articles