2015-09-06 19 views
29

Per la mia app iOS Ho un modello simileCome posso creare un set di oggetti personalizzati (Swift)?

class Person { 
    var Id: Int 
    var Name: String 

    init(id: Int, name: String?) { 
     self.Id = id 
     self.Name = name ?? "" 
    } 
} 

poi in seguito nel mio ViewController quando carico i dati dal server aggiungo alcune persone di una matrice

class ViewController: UIViewController { 
    var people:[Person] = [] 

    override func viewDidLoad() { 
     self.loadPeople() 
    } 

    func loadPeople() { 
     // This data will be coming from a server request 
     // so is just sample. It could have users which 
     // already exist in the people array 

     self.people.append(Person(id: "1", name: "Josh")) 
     self.people.append(Person(id: "2", name: "Ben")) 
     self.people.append(Person(id: "3", name: "Adam")) 
    } 
} 

Quello che sono ora provare a fare questo è trasformare l'array people in un Set<Person> in modo che non aggiunga duplicati. È possibile fare o devo cambiare la mia logica?

risposta

38

per rendere set di Person è necessario per renderlo conforme alle equatable e protocolli hashable:

class Person: Equatable, Hashable { 
    var Id: Int 
    var Name: String 

    init(id: Int, name: String?) { 
     self.Id = id 
     self.Name = name ?? "" 
    } 

    var hashValue: Int { 
     get { 
      return Id.hashValue << 15 + Name.hashValue 
     } 
    } 
} 

func ==(lhs: Person, rhs: Person) -> Bool { 
    return lhs.Id == rhs.Id && lhs.Name == rhs.Name 
} 

quindi è possibile utilizzare un insieme di persone in questo modo:

var set = Set<Person>() 
set.insert(Person(id: 1, name: "name")) 
+2

Personalmente uso 'XOR' per combinare hash, ma +1 per includere il protocollo' Hashable' nella risposta. –

+4

hastable eredita da Equitable, quindi dichiarare la classe come 'class Person: Hashable {...}' sarebbe sufficiente. Naturalmente, aggiungere Equitable esplicitamente non fa male. –

+1

@ egor.zhdan potresti spiegare i bit del turno 15 parte e perché hai usato 15 lì? –

6

Con Swift 2.0, hashable Equitable è una parte di NSObject. Tutto ciò che devi fare è sovrascrivere "isEqual" e "var hash:" per la proprietà di interesse. In questo caso: "Id", Set esclude gli oggetti Person con ID identici.

class Person: NSObject { 
     var Id: Int 
     var Name: String 

     init(id: Int, name: String?) { 
      self.Id = id 
      self.Name = name ?? "" 
     } 

     override var hash: Int { 
     return Id.hashValue 
    } 

     override func isEqual(object: AnyObject?) -> Bool { 
      guard let rhs = object as? Person else { 
       return false 
      } 
      let lhs = self 

      return lhs.Id == rhs.Id 
     } 


    } 

      func mergeArrays(){ 
     let person1 = Person(id: 1, name: "Tom") 
     let person2 = Person (id: 2, name: "John") 
     let person3 = Person(id: 3, name: "Adam") 


     let downloadedPeople = [person1,person2] //[{NSObject, Id 1, Name "Tom"}, {NSObject, Id 2, Name "John"}] 

     let peopleStoredLocally = [person1,person3] //[{NSObject, Id 1, Name "Tom"}, {NSObject, Id 3, Name "Adam"}] 

     let downloadedPeopleSet = Set(downloadedPeople) //{{NSObject, Id 2, Name "John"}, {NSObject, Id 1, Name "Tom"}} 


     let mergedSet = downloadedPeopleSet.union(peopleStoredLocally) //{{NSObject, Id 2, Name "John"}, {NSObject, Id 3, Name "Adam"}, {NSObject, Id 1, Name "Tom"}} 


     let mergedArray = Array(mergedSet)//[{NSObject, Id 2, Name "John"}, {NSObject, Id 3, Name "Adam"}, {NSObject, Id 1, Name "Tom"}] 

    } 
+5

Probabilmente non dovresti usare i tipi objC per un'app rapida, a meno che tu non sia realmente necessario. Quindi consiglierei di usare i protocolli standalone invece di ereditare da NSObject. – herby

Problemi correlati