2017-09-20 3 views
0

NSObject, NSCodingに準拠したカスタムクラスPlayerがあります。 Playerオブジェクトは、私が遭遇していた問題のid: String!SwiftのNSObjectのデフォルト比較をオーバーライドする方法

一つでインスタンス化されて、私は次のような操作を実行するときです:

let listOfPlayers = [Player]() 
//populate listOfPlayers 
if listOfPlayers.contains(aPlayer) ... 

具体的には、containsは、メモリポインタに基づいて結果を返しますし、 idの値に基づいていません。このように、私はtrue、場合によってはfalseとなるでしょう。

私はデフォルトの比較メソッドをオーバーライドしたい、と次のようでした:

func isEqual(object: AnyObject?) -> Bool { 
    if let otherPlayer = object as? Player { 
     return self.id == otherPlayer.id 
    } 
    return false 
} 


static func == (lhs: Player, rhs: Player) -> Bool { 
    return lhs.id == rhs.id 
} 

しかし、これらの機能が実行されていません。それだけでid要素を比較しているので、顧客のコンパレータを持っているための正しい方法は何ですか

私も overrideを追加しようとしましたが、それはエラーを返す「メソッドは、そのsuperclass`から任意のメソッドをオーバーライドしていないのですか?

おかげ

+2

'isEqual'を書いたときに、コンパイラが' override'を挿入しなかったとき、それは手がかりでした! – matt

+1

あなたはdownvoteが何であるか説明できますか? – daspianist

答えて

2

NSObjectisEqual方法はAny? パラメータを取りますので、あなたは正しいメソッドをオーバーライドしていない、それはそれが呼び出されない理由 です。

またvar hash: Int(等しいオブジェクトが同じハッシュを持つ必須)をオーバーライドする必要があります - それ以外のオブジェクトはハッシュ可能コレクション(セット、辞書)に誤って動作します:

class Player: NSObject { 
    let id: String 

    init(id: String) { self.id = id } 

    override func isEqual(_ object: Any?) -> Bool { 
     if let other = object as? Player { 
      return self.id == other.id 
     } else { 
      return false 
     } 
    } 

    override var hash: Int { 
     return id.hashValue 
    } 
} 

一部のテスト:

let p1 = Player(id: "a") 
let p2 = Player(id: "a") 

print(p1 == p2) // true 
print(p1 != p2) // false 

// Native Swift set: 
let set = Set([Player(id: "x"), Player(id: "y"), Player(id: "z")]) 
print(set.contains(Player(id: "y"))) // true 

// Foundation set: 
let nsset = NSSet(objects: Player(id: "x"), Player(id: "y"), Player(id: "z")) 
print(nsset.contains(Player(id: "y"))) // true 
+0

私は再びkoolaidを飲んでいます...' return(オブジェクトとして?Player)。 map {$ 0.id == other.id} ?? false' – Alexander

+0

@Alexander:IOSCC(国際的に難読化されたスウィフトコードコンテスト)への提出? –

+0

確かにそうかもしれません!オプションの 'map'と' flapMap'について多くの人が知り得ないことは残念です。これは本当に素晴らしい構文を可能にします – Alexander

0

私が遊び場に次のコードを投げた

class Player : NSObject { 
    var id : String = "" 

    static func == (lhs: Player, rhs: Player) -> Bool { 
     print("We checked here") 
     return lhs.id == rhs.id 
    } 
} 

//Direct comparison will call our function. 
if Player() == Player() { 
    print("yay") 
} 

let players : [Player] = [Player()] 

//Even though Player() has same id, it is new object in memory so this won't evaluate as true when comparing with `contains()`, 
//hence why "we checked here" isn't called again. 
if players.contains(Player()) { 
    print("Dang we suck") 
} 

//Could check with something like this if you want to check your array for a particular id. 
if players.contains(where: {$0.id == Player().id }) { 
    print("Im awesome") 
} 

出力:!。

We checked here 
yay 
Im awesome 

私はidではなく、メモリ内の同じオブジェクトであるかどうかをチェックするダイレクトイコール比較とは対照的に、トリプルイコールの比較===を使用しています。ご覧のとおり、We checked hereは直接比較でのみ呼び出されます。 contains(where: predicate)メソッドを使用して特定の条件を取得できます。スウィフト3のよう

+0

Annnnndブーム:http://swift.sandbox.bluemix.net/#/repl/59c2ba766032437898077527 – Alexander

+1

'NSObject'の'!= 'と' == 'が' isEqual'を呼び出します。 'NSObject'サブクラスの等価性を適切に定義するには、' isEqual'をオーバーライドする必要があります。 – Alexander

+1

http://swift.sandbox.bluemix.net/#/repl/59c2bd5b052a1b77c5e05898特に '!= '演算子をオーバーライドする必要があります。そうしないと、メモリアドレスをチェックするデフォルトの実装に変更されます。 – NSGangster

関連する問題