2015-09-22 30 views
6

içeriyorken beklenmedik şekilde çalışma ayarlanmadı Kod tabanımızı Swift2'ye yükselttikten sonra olağandışı bir sorunla karşılaştım. Set, beklenmedik şekilde birleştirme ya da birleştirme değildir.Swift 2.0 NSObject alt sınıfı

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 

Yeni Set, dahili işlemler için hashValue kullanılmıyor gibi görünüyor. Herhangi bir fikir, bir hata ya da bu sorunun çözümü için bir yol mu?

cevap

11

Kodunuzla biraz oynandım.

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 

Eğer NSObject devralan edildi senin == aşırı yük aslında yürütülmekte olan edilmedi: Ben artık NSObject sınıflara, ancak bunun yerine Hashable protokolüne uygun çalışıp çalışmadığını elde edebildi. Bu NSObject çalışmak istiyorsanız, isEquals geçersiz olurdu: Bu Soru/Cevap çarpana kadar

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

Teşekkür ederiz! Bu problemi MKAnnotation alt sınıfında (NSObject'i de genişletmesi gerekiyor) yapıyordum. Konuyla ilgili bazı belgelerin bağlantısı var mı? – brki

+1

Hem IsEqual hem de hashValue, Swift 3 –

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 

Bunun için doğru cevabı arayan zaman geçirdi. Neler olduğunu görmek için XCode Playground'daki temel bilgilere geri dönmüştüm. Swift Set'daki NSObject alt sınıflarını kullanmak, daha fazla okunabilir kod oluşturur.

+0

'da NSObject ile doğru şekilde Ayarlamak için gerekli gibi görünüyor. Neden bu kadar çok insan diğer cevabı seçtiğini bilmiyorum. Benim için, bu değerli ve doğru olanıdır. Çok teşekkür ederim. –

+0

Sadece 'NSObjectProtocol' ifadesinde gereklidir, eğer func isEqual (_ object: Any?) -> Bool 'seçeneğini geçersiz kılarsanız, var hash: Int {get}' yi de geçersiz kılmalısınız. Dokümanlardaki gibi, “İki nesne eşitse (isEqual (_ :) yöntemi tarafından belirlendiği gibi), aynı karma değere sahip olmaları gerekir. '. https://developer.apple.com/reference/objectivec/nsobjectprotocol/1418859-hash –