Перегрузка оператора "<", объявленная в классе Swift, иногда не вызывается при использовании в Objective-C

Я столкнулся со странной проблемой, связанной с совместимостью Swift/Objective-C. Дело в том, что это:

у меня есть @objc public class GKDistance:NSObject,NSCoding,Comparable написано в Swift. Чтобы сравнить расстояния, я добавил перегрузку оператора для < следующее:

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

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

Затем он используется в методе Objective-C следующим образом:

if (distance < averageDistance){
    // code
}

Когда вызывается метод Objective-C, я могу добавить print() заявление и точка останова в < метод подтверждения, когда используется перегрузка оператора. В одном случае он таинственным образом пропускает перегрузку оператора, определенную в Swift, и использует обычный компаратор Objective-C между двумя объектами GKDistance.

Когда бегать с distance.value == 2375.1842554877021 а также averageDistance.value == 75.671794891357421, distance < averageDistance возвращается trueперегрузка оператора Swift никогда не срабатывает, и Objective-C выполняет код внутри условного выражения.

Если я преобразую рассматриваемый метод Objective C в Swift, он будет работать так, как ожидалось, но я обеспокоен тем, что в нашем приложении есть другие сравнения GKDistance в различных методах Objective C, которые могут не увидеть перегрузку оператора Swift.

Кто-нибудь сталкивался с подобными проблемами с совместимостью Swift/Objective-C, поскольку это касается перегрузки оператора?

1 ответ

Решение

Ваш

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

Это - как и все операторы Swift - функция верхнего уровня, а функции верхнего уровня не экспортируются в Objective-C, см. "Совместимость типов Swift" в "Взаимодействие с API-интерфейсами Objective-C".

Также обратите внимание, что вы не можете переопределить операторы (например, <) в (Objective-)C, см., например,

Поэтому в

if (distance < averageDistance) {
    // code
}

сравниваются только два указателя, и условие истинно, если объект, на который указывает distance находится в более низком адресе памяти, чем указатель объекта на averageDistance (что, очевидно, не то, что вы хотели).

Что вы могли бы сделать, это реализовать compare: метод в вашем классе, похожий на один из NSString или же NSNumber,

Обратите внимание, что для NSObject подклассы, вы должны переопределить isEqual: вместо реализации == сравнить

Другие вопросы по тегам