2015-06-28 1 views
11

Хорошо, что-то странное происходит при написании собственный равен оператору для NSObject подклассов Swift 2.0, как это:Ошибка с оператором equals и NSObjects в Swift 2.0?

func ==(lhs: MyObject, rhs: MyObject) -> Bool { 
    return lhs.identifier == rhs.identifier 
} 

Для класса, который выглядит следующим образом:

class MyObject: NSObject { 
    let identifier: String 
    init(identifier: String) { 
     self.identifier = identifier 
    } 
} 

Это работало только штраф в Swift 1.2 и ниже. Это все еще вид работ:

let myObject1 = MyObject(identifier: "A") 
let myObject2 = MyObject(identifier: "A") 
let result = (myObject1 == myObject2) 
// result is true 

Пока все хорошо, но что, если обе переменные были опционными? не

let myObject1: MyObject? = MyObject(identifier: "A") 
let myObject2: MyObject? = MyObject(identifier: "A") 
let result = (myObject1 == myObject2) 
// result is false, equals operator was never even called 

И одна вещь, которая больше не работает:

let myObject1 = MyObject(identifier: "A") 
let myObject2 = MyObject(identifier: "A") 
let result = (myObject1 == myObject2) 
// result is true 
let result = (myObject1 != myObject2) 
// result is true, equals operator was never even called 

Таким образом, очевидно, = больше не вызывает оператор == и сводит на нет его. Кажется, что просто сравнивайте примеры при использовании! =

Все это происходит только тогда, когда ваш класс является подклассом NSObject (прямо или косвенно). Когда это не так, все работает так, как вы ожидали.

Может ли кто-нибудь сказать мне, является ли это новой «функцией» в Swift 2.0 или просто неприятной ошибкой?

+0

вы имели в виду, чтобы написать '==', вместо '=', в вашем файле '' == функции? Может быть причиной странного поведения, я еще не проверял это. – ABakerSmith

+0

К сожалению, это не причина (см. Мой ответ ниже), но вы правы, он должен быть '==' – Qbyte

+0

К сожалению, опечатка. Но это действительно не моя проблема. –

ответ

9

К сожалению, я не знаю, считается ли это признаком или нет (я так не думаю). Эта проблема возникает, если какой-либо класс подклассы класса, который соответствует Equatable (например, NSObject, он сравнивает фактические экземпляры). Так что если вы только «переопределить» == оператор подкласса все другие операторы, такие как:

func !=<T : Equatable>(lhs: T, rhs: T) -> Bool 
func ==<T : Equatable>(lhs: T?, rhs: T?) -> Bool 
func ==<T : Equatable>(lhs: [T], rhs: [T]) -> Bool 

где T ограничивается быть Equatable Swift использует == оператор BaseClass. Как (трудоемкий) временное решение может привести к перегрузке всех операторов равенства вы должны использовать следующим образом:

func !=(lhs: MyObject, rhs: MyObject) -> Bool { ... } 
func ==(lhs: MyObject?, rhs: MyObject?) -> Bool { ... } 
func ==(lhs: [MyObject], rhs: [MyObject]) -> Bool { ... } 

Edit: Причина

Причиной такого поведения является то, что если подкласс соответствует EquatableSelf самообеспечения определяется таким классом. Поэтому каждый раз, когда вызывается == с (общим) типом, который соответствует Equatable, он вызывает только оператор исходного соответствующего класса.

+0

Разве это не отвечает на ваш вопрос? – Qbyte

+2

Это все еще присутствует в Xcode 7 GM. Вы когда-нибудь узнавали, есть ли намеренное изменение? – Bill

+0

@Bill Я узнал, что это поведение даже существует в Swift 1.2, и я отредактировал свой ответ (причина такого поведения). – Qbyte

10

Я думаю, что это поведение следует считать ошибкой (все еще присутствующей на Xcode 7 beta 6), но есть многообещающее временное решение: переопределить NSObject -isEqual вместо того, чтобы реализовать оператор Swift ==.

class MyObject: NSObject { 
    let identifier: String 
    init(identifier: String) { 
     self.identifier = identifier 
    } 
    override func isEqual(object: AnyObject?) -> Bool { 
     guard let rhs = object as? MyObject else { 
      return false 
     } 
     let lhs = self 

     return lhs.identifier == rhs.identifier 
    } 
} 

я нашел другую ссылку на проблему, с большим количеством примеров кода, здесь: http://mgrebenets.github.io/swift/2015/06/21/equatable-nsobject-with-swift-2/

+0

Также в версии Xcode 7! –

0

kylealanhale's answer не работает с NSManagedObject (объяснил here), поэтому я создал новый протокол NSObjectSubclassEquatable, который можно использовать для сравнение NSobject подклассы.

infix operator =~= {} 

public protocol NSObjectSubclassEquatable { 

    static func compare(lhs: Self,_ rhs: Self) -> Bool 
} 


public func =~=<T : NSObjectSubclassEquatable>(lhs: T, rhs: T) -> Bool { 

    return T.compare(lhs, rhs) 
} 

func =~=<Element : NSObjectSubclassEquatable>(lhs: [Element], rhs: [Element]) -> Bool { 
    for (lhsElement,rhsElement) in zip(lhs, rhs) { 
    if !(lhsElement =~= rhsElement) { 
     return false 
    } 
    } 
    return true 
} 

Пример:

class Point: NSObject { 

    var x: Int 
    var y: Int 

    init(_ x: Int,_ y: Int) { 
    self.x = x 
    self.y = y 
    } 
} 

extension Point: NSObjectSubclassEquatable { 

    static func compare(lhs: Point,_ rhs: Point) -> Bool { 
    return lhs.x == rhs.x && lhs.y == rhs.y 
    } 
} 

Point(1,2) =~= Point(1,2) // Prints true 
[Point(1,2)] =~= [Point(1,2)] // Prints true