2015-06-28 17 views
11

Ok, một cái gì đó kỳ lạ đang xảy ra khi viết riêng bạn bằng nhà điều hành cho lớp con NSObject trong Swift 2.0 như thế này:Lỗi với bằng toán tử và NSObject trong Swift 2.0?

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

Đối với một lớp trông như thế này:

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

này được sử dụng để làm việc chỉ tốt trong Swift 1.2 trở xuống. Nó vẫn hoạt động:

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

Cho đến nay rất tốt, nhưng nếu cả hai biến là tùy chọn thì sao?

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 

Và một điều khác mà không còn hoạt động:

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 

Vì vậy, rõ ràng, = không còn gọi là toán tử == và phủ nhận nó. Dường như chỉ so sánh các trường hợp thay vì khi sử dụng! =

Tất cả điều này chỉ xảy ra khi lớp của bạn là lớp con của NSObject (trực tiếp hoặc gián tiếp). Khi không, mọi thứ hoạt động giống như bạn mong đợi.

Bất cứ ai có thể cho tôi biết nếu đây là một 'tính năng' mới trong Swift 2.0 hay chỉ là một lỗi khó chịu?

+0

Ý của bạn là để viết '== ', thay vì' = ', trong' ==' chức năng của bạn? Có thể là nguyên nhân của hành vi kỳ lạ, tuy nhiên tôi chưa thử nghiệm điều này. – ABakerSmith

+0

Thật không may đây không phải là nguyên nhân (xem câu trả lời của tôi dưới đây) nhưng bạn đã đúng, nó phải là '== ' – Qbyte

+0

Xin lỗi, lỗi đánh máy. Nhưng đó thực sự không phải là vấn đề của tôi. –

Trả lời

9

Thật không may tôi không biết đây có phải là một tính năng hay không (tôi không nghĩ vậy). Vấn đề này xảy ra nếu bất kỳ lớp nào phân lớp một lớp phù hợp với Equatable (như NSObject; nó so sánh các phiên bản thực tế). Vì vậy, nếu bạn chỉ "ghi đè" các == điều hành của lớp con tất cả các nhà khai thác khác như:

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

nơi T là hạn chế được Equatable Swift sử dụng == điều hành của baseclass. As (tốn thời gian) workaround bạn có thể quá tải tất cả các nhà khai thác bình đẳng bạn phải sử dụng như sau:

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

Edit: Lý do

Lý do cho hành vi này là nếu một lớp con phù hợp với Equatable số Self của yêu cầu tự xác định là lớp này. Vì vậy, mỗi khi == được gọi với loại (chung) phù hợp với Equatable, nó chỉ gọi toán tử của lớp phù hợp ban đầu.

+0

Điều này không trả lời câu hỏi của bạn? – Qbyte

+2

Điều này vẫn còn hiện diện trong Xcode 7 GM. Bạn đã bao giờ tìm ra nếu đó là một sự thay đổi có chủ ý? – Bill

+0

@Bill Tôi phát hiện ra rằng hành vi này thậm chí còn tồn tại trong Swift 1.2 và tôi đã chỉnh sửa câu trả lời của mình (lý do của hành vi này). – Qbyte

10

Tôi nghĩ rằng hành vi này nên được coi là một lỗi (vẫn tồn tại như của Xcode 7 beta 6), nhưng có một giải pháp tạm thời hy vọng: ghi đè lên NSObject -isEqual thay vì triển khai toán tử == của 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 
    } 
} 

Tôi tìm thấy một tài liệu tham khảo cho vấn đề, với nhiều ví dụ mã, ở đây: http://mgrebenets.github.io/swift/2015/06/21/equatable-nsobject-with-swift-2/

+0

Cũng trong bản phát hành Xcode 7! –

0

kylealanhale's answer không làm việc với NSManagedObject (giải thích here), vì vậy tôi đã tạo ra một giao thức mới NSObjectSubclassEquatable mà bạn có thể sử dụng cho so sánh NSobject lớp con.

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 
} 

Ví dụ:

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 
Các vấn đề liên quan