2015-09-22 2 views
6

私たちのコードベースをSwift2にアップグレードした後、私は異常な問題に遭遇しました。集合は、期待どおりに減算も結合もしません。Swift 2.0 NSObjectサブクラスを含むときに期待通りに動作しません。

class A: NSObject { 
    let h: Int 

    init(h: Int) { 
     self.h = h 
    } 

    override var hashValue: Int { 
     return h 
    } 
} 

func ==(lhs: A, rhs: A) -> Bool { 
    return lhs.hashValue == rhs.hashValue 
} 

let a = A(h: 1) 
let b = A(h: 1) 

var sa = Set([a]) 
let sb = Set([b]) 

sa.subtract(sb).count // Swift1.2 prints 0, Swift 2 prints 1 

sa.contains(a) // Swift1.2 true, Swift 2 true 
sa.contains(b) // Swift1.2 true, Swift 2 false 

新しいセットは内部操作にhashValueを使用していません。どのようなアイデアは、バグ、またはこの問題を回避する方法ですか?

答えて

11

私は少しあなたのコードで遊んだ。

class A: Hashable { 
    let h: Int 

    init(h: Int) { 
     self.h = h 
    } 

    var hashValue: Int { 
     return h 
    } 

} 

func ==(lhs: A, rhs: A) -> Bool { 
    return lhs.hashValue == rhs.hashValue 
} 

let a = A(h: 1) 
let b = A(h: 1) 

var sa = Set([a]) 
let sb = Set([b]) 

sa.subtract(sb).count // Swift1.2 prints 0, Swift 2 prints 1 

sa.contains(a) // Swift1.2 true, Swift 2 true 
sa.contains(b) // Swift1.2 true, Swift 2 false 

a.hashValue == b.hashValue 

あなたがNSObjectのから継承された、あなたの==過負荷が実際に実行されていませんでした。私はそれはもはやNSObjectのサブクラスを、代わりにハッシュ可能プロトコルに準拠することで動作させることができました。あなたはこれがNSObjectので作業する場合は、isEqualsをオーバーライドする必要があるだろう:私はこの質問/回答を打つまで

override func isEqual(object: AnyObject?) -> Bool { 
    if let object = object as? A { 
     return object.h == self.h 
    } else { 
     return false 
    } 
} 
+0

ありがとうございました!私はMKAnnotationサブクラス(NSObjectを拡張する必要もあります)でこの問題を抱えていました。あなたはそのテーマに関するいくつかの文書へのリンクを持っていますか? – brki

+1

スウィフト3でNSObjectを正しく設定するためにisEqualとhashValueの両方が必要なようです –

2
//: Playground - noun: a place where people can play 

import Foundation 

class X: NSObject { 
    var x:String 
    var y:Int 

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

    override var hashValue: Int { 
     return x.hashValue^y.hashValue 
    } 

    override func isEqual(object: AnyObject?) -> Bool { 
     if let rhs = object as? X { 
      return x == rhs.x && y == rhs.y 
     } else { 
      return false 
     } 
    } 
} 

func == (lhs:X, rhs:X) -> Bool { 
    return lhs.isEqual(rhs) 
} 

let x = X(x: "x1", y: 1) 
let y = X(x: "x1", y: 1) 
X(x: "x1", y: 1) == X(x: "x1", y: 1) // Swift 'x == y' (true) 
x.isEqual(y)       // Obj-C '[x isEqual: y]' (true) 

var s:Set<X> = [X(x: "x1", y: 1)] 
s.count // count == 1 
s.insert(X(x: "x2", y: 1)) 
s.count // count == 2 
s.insert(X(x: "x1", y: 1)) 
s.count // count == 2 
s.insert(X(x: "x2", y: 1)) 
s.count // count == 2 

私はこれに対する正しい答えを探して時間を過ごしました。私は何が起こっていたのかを見るためにXCodeプレイグラウンドの基本に戻っていました。 Swift SetのサブクラスNSObjectを使用すると、より読みやすいコードが作成されます。

+0

なぜ多くの人が他の答えを選んだのかわかりません。私のために、これは貴重で正しいものです。どうもありがとうございました。 –

+0

'NSObjectProtocol'では' func isEqual(_ object:Any?) - > Bool'をオーバーライドする場合、 'var hash:Int {get} 'をオーバーライドする必要があります。ドキュメントのように、2つのオブジェクトが等しい場合(isEqual(_ :)メソッドで決まる)、同じハッシュ値を持つ必要があります。 '。 https://developer.apple.com/reference/objectivec/nsobjectprotocol/1418859-hash –

関連する問題