5 Stimmen

Hilfe bei isEquals und Hash in iphone

Ich überschreibe also isEquals y hash benutzerdefinierte Objekte zu vergleichen, um Duplikate aus einer NSArray . Das Problem ist, dass ich einige Werte in der Liste fehlen, die keine doppelten Elemente enthält, und es scheint, dass meine hash o isEquals Umsetzung falsch ist. Das benutzerdefinierte Objekt ist ein Kursobjekt, das einige Variablen wie: id y name Ich werde den Code hier einfügen:

- (BOOL)isEqual:(id)object {
    if ([object isKindOfClass:[Course self]]) {
        return YES;
    } 
    if(self == object){
        return YES;
    }
    else {
        return NO;
    }
}

- (unsigned)hash {

    NSString *idHash = [NSString stringWithFormat: @"%d", self._id];
    return [idHash hash];
}

Dann, nach der Abfrage der Datenbank ich die Werte in einem Array und dann in einem Satz, der die doppelten Elemente wie diese entfernen sollte:

NSMutableSet *noDuplicates = [[NSMutableSet alloc] initWithArray:tempResults];

Können Sie sehen, was ich in der isEquals o hash Umsetzung?

Herzlichen Dank.

11voto

JeremyP Punkte 81782

Schritt 1. Entscheiden Sie, welche Instanzvariablen/Zustände zur Bestimmung der Gleichheit verwendet werden. Es ist eine gute Idee, sicherzustellen, dass Eigenschaften für sie existieren (sie können private Eigenschaften sein, die in einer Klassenerweiterung wenn Sie möchten).

Schritt 2. Schreiben Sie eine Hash-Funktion, die auf diesen Instanzvariablen basiert. Wenn alle Eigenschaften, die zählen, Objekte sind, können Sie einfach ihre Hashes miteinander xorieren. Sie können auch direkt C-Ints usw. verwenden.

Schritt 3. Schreiben Sie isEqual: Das übliche Muster ist wahrscheinlich, zunächst zu prüfen, ob beide Objekte in der Klasse oder einer Unterklasse der Methode sind, in der isEqual: definiert ist, und dann die Gleichheit aller Eigenschaften zu prüfen.

Wenn also eine Klasse Person eine Namenseigenschaft (Typ NSString) und eine Zahleneigenschaft (Typ int) hat, die zusammen eine eindeutige Person definieren, hash sein könnte:

-(NSUInteger) hash
{
    return [[self name] hash] ^ [self number];
}

isEqual: sein könnte

-(BOOL) isEqual: (id) rhs
{
    BOOL ret = NO;
    if ([rhs isKindOfClass: [Person class]]) // do not use [self class]
    {
        ret = [[self name] isEqualToString: [rhs name]] && [self number] == [rhs number];
    } 
    return ret;
}

Ich glaube nicht, dass es als explizite Anforderung im Dokument angegeben ist, aber es wird wahrscheinlich angenommen, dass die Gleichheit symmetrisch und transitiv ist, d.h.

  • [a isEqual: b] == [b isEqual: a] für alle a und b
  • [a isEqual: b] && [b isEqual: c] impliziert [a isEqual: c] für alle a, b, c

Sie müssen also vorsichtig sein, wenn Sie die isEqual: für Unterklassen, um sicherzustellen, dass es in beide Richtungen funktioniert. Dies ist auch der Grund, warum der Kommentar, verwenden Sie nicht [self class] oben.

3voto

Lily Ballard Punkte 175449

Nun, Ihr isEqual: Implementierung testet eigentlich nur, ob die beiden Objekte dieselbe Klasse sind. Das ist ganz und gar nicht korrekt. Ohne die Details Ihres Objekts zu kennen, weiß ich nicht, wie eine gute Implementierung aussehen würde, aber sie würde wahrscheinlich der folgenden Struktur folgen

- (BOOL)isEqual:(id)object {
    if ([object isMemberOfClass:[self class]]) {
        // test equality on all your important properties
        // return YES if they all match
    }
    return NO;
}

In ähnlicher Weise basiert Ihr Hash auf der Umwandlung eines int in eine Zeichenkette und der Übernahme des Hashes. Sie könnten auch einfach die int selbst als Ihre Hash zurückgeben.

2voto

Ihr Code verstößt gegen das Prinzip "Gleiche Objekte sollten gleiche Hashes haben". Ihre Hash-Methode generiert einen Hash aus self._id und berücksichtigt diesen Wert nicht, wenn Sie die Gleichheit der Objekte bewerten.

Konzepte der Objective-C-Programmierung hat einen Abschnitt über Introspektion, in dem dieses Thema anhand von Beispielen behandelt wird. isEqual soll die Frage beantworten, ob zwei Objekte gleichwertig sind, auch wenn es sich um zwei verschiedene Instanzen handelt. Sie wollen also ein BOOL zurückgeben, das angibt, ob das Objekt als äquivalent betrachtet werden sollte. Wenn Sie isEqual nicht implementieren, wird es einfach den Zeiger auf Gleichheit vergleichen, was wahrscheinlich nicht das ist, was Sie wollen.

- (BOOL)isEqual:(id)object {
    BOOL result = NO;

    if ([object isKindOfClass:[self class]]) {
        result = [[self firstName] isEqualToString:[object firstName]] && 
        [[self lastName] isEqualToString:[object lastName]] &&
        [self age] == [object age];
    }

    return result;
}

より NSObject Protokoll-Referenz :

Gibt eine Ganzzahl zurück, die als Tabellenadresse in einer Hashtabellenstruktur Struktur verwendet werden kann.

Wenn zwei Objekte gleich sind (wie mit der Methode isEqual: festgestellt), müssen sie müssen sie den gleichen Hash-Wert haben. Dieser letzte Punkt ist besonders wichtig wichtig, wenn Sie Hash in einer Unterklasse definieren und beabsichtigen, Instanzen dieser Unterklasse in eine Sammlung aufzunehmen.

- (NSUInteger)hash {
    NSUInteger result = 1;
    NSUInteger prime = 31;

    result = prime * result + [_firstName hash];
    result = prime * result + [_lastName hash];
    result = prime * result + _age;

    return result;
}

Was also zwei Objekte als gleich definiert, wird vom Programmierer und seinen Bedürfnissen bestimmt. Unabhängig davon, welche Methodik für die Gleichheit entwickelt wird, sollten gleiche Objekte gleiche Hashes haben.

-14voto

Bharath Booshan Punkte 211

So implementieren Sie Hash und isEqual (zumindest die, die für mich zum Zweck der Identifizierung von Duplikaten funktioniert)

Hash-Funktion

Die Apple Doc sagt, dass der Hash von zwei Objekten gleich sein sollte für diejenigen, die als gleich (logisch) sind.

-(unsigned int)hash  
{  
    return 234;//some random constant  
} 

isEqual: Die Implementierung der Methode würde etwa so aussehen

-(BOOL)isEqual:(id)otherObject  
{  
  MyClass *thisClassObj = (MyClass*)otherObject;

  *// this could be replaced by any condition statement which proves logically that the two object are same even if they are two different instances* 

return ([thisClassObj primaryKey] == [self primaryKey]);

}

Weitere Informationen finden Sie hier: Techniken zur Implementierung von -hash bei veränderbaren Cocoa-Objekten

Implementierung von -hash / -isEqual: / -isEqualTo...: für Objective-C-Sammlungen

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X