2015-06-28 8 views
11

Ok, etwas Seltsames geschieht, wenn Ihr eigenes Schreiben Gleichheitsoperator für NSObject Subklassen in Swift 2.0 wie folgt aus:Fehler mit Gleichheitsoperator und NSObjects in Swift 2.0?

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

Für eine Klasse, die wie folgt aussieht:

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

Diese verwendet nur arbeiten gut in Swift 1.2 und darunter. Es funktioniert immer noch Art von:

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

So weit so gut, aber was ist, wenn beide der Variablen Optionals waren?

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 

Und eine andere Sache, die nicht mehr funktioniert:

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 

So offenbar = keine Anrufe mehr den Operator == und negiert es. Es scheint nur die Instanzen stattdessen zu vergleichen, wenn Sie verwenden! =

All dies geschieht nur, wenn Ihre Klasse eine Unterklasse von NSObject (direkt oder indirekt) ist. Wenn das nicht der Fall ist, funktioniert alles so, wie Sie es erwarten würden.

Kann mir jemand sagen, ob dies ein neues "Feature" in Swift 2.0 oder nur ein böser Bug ist?

+0

Meinten Sie schreiben '==', statt '=', in der '==' Funktion? Könnte die Ursache für das seltsame Verhalten sein, das habe ich allerdings nicht getestet. – ABakerSmith

+0

Leider ist das nicht die Ursache (siehe meine Antwort unten), aber Sie haben Recht, es sollte '==' – Qbyte

+0

Sorry, Tippfehler sein. Aber das war tatsächlich nicht mein Problem. –

Antwort

9

Leider weiß ich nicht, ob dies als eine Funktion betrachtet wird oder nicht (glaube ich nicht). Dieses Problem tritt auf, wenn eine Klassenunterklasse eine Klasse, die Equatable entspricht (wie NSObject; es vergleicht tatsächliche Instanzen). Also, wenn Sie nur „überschreiben“ die == Betreiber der Unterklasse alle anderen Operatoren wie:

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

wo T eingeschränkt ist Equatable Swift nutzt die == Betreiber der Basisklasse zu sein. Als (zeitaufwendig) umgehen Sie die Gleichheitsoperatoren alles, was Sie wie so zu verwenden, haben überlasten:

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

Edit: Der Grund

Der Grund für dieses Verhalten ist, dass, wenn eine Unterklasse entspricht Equatable wird die Self der Eigenanforderung als diese Klasse bestimmt. Jedes Mal, wenn der == mit einem (generischen) Typ aufgerufen wird, der Equatable entspricht, ruft er nur den Operator der ursprünglichen konformen Klasse auf.

+0

Beantwortet das nicht Ihre Frage? – Qbyte

+2

Dies ist immer noch in der Xcode 7 GM vorhanden. Hast du jemals herausgefunden, ob es eine absichtliche Änderung ist? – Bill

+0

@Bill Ich habe herausgefunden, dass dieses Verhalten sogar in Swift 1.2 existiert und ich habe meine Antwort bearbeitet (Grund dieses Verhaltens). – Qbyte

10

Ich denke, dieses Verhalten sollte als ein Fehler betrachtet werden (noch vorhanden von Xcode 7 Beta 6), aber es gibt eine hoffentlich temporäre Problemumgehung: überschreiben NSObject -isEqual anstelle von Swifts ==-Operator zu implementieren.

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 
    } 
} 

fand ich eine andere Verweis auf das Problem, mit mehr Code-Beispiele, hier: http://mgrebenets.github.io/swift/2015/06/21/equatable-nsobject-with-swift-2/

+0

Auch in Xcode 7 Release! –

0

kylealanhale's answer funktioniert nicht mit NSManagedObject (here erklärt), so habe ich ein neues Protokoll NSObjectSubclassEquatable, die Sie verwenden können, Vergleichen NSobject Unterklassen.

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 
} 

Beispiel:

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