Перегрузка оператора "<", объявленная в классе 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:
вместо реализации ==
сравнить