Wenn Sie mit objectAtIndex: kein Objekt von einem NSSet erhalten können, wie können Sie dann Objekte abrufen?
Wenn Sie mit objectAtIndex: kein Objekt von einem NSSet erhalten können, wie können Sie dann Objekte abrufen?
Antworten:
Es gibt mehrere Anwendungsfälle für einen Satz. Sie können mit (z. B. mit enumerateObjectsUsingBlock
oder NSFastEnumeration) auflisten, aufrufen containsObject
, um die Mitgliedschaft zu testen anyObject
, ein Mitglied (nicht zufällig) abrufen oder es mit in ein Array (in keiner bestimmten Reihenfolge) konvertieren allObjects
.
Ein Set ist geeignet, wenn Sie keine Duplikate möchten, sich nicht um die Reihenfolge kümmern und schnelle Mitgliedschaftstests wünschen.
member:
Nachricht senden . Wenn es zurückkehrt nil
, enthält die Menge kein Objekt, das dem Objekt entspricht, das Sie übergeben haben. Wenn ein Objektzeiger zurückgegeben wird, bezieht sich der zurückgegebene Zeiger auf das Objekt, das sich bereits in der Menge befindet. Die Objekte in der Menge implementieren muss hash
und isEqual:
für diese nützlich sein.
hash
Bedürfnisse umgesetzt werden; es würde einfach viel schneller gehen, wenn du das tust.
hash
im NSObject-Protokoll: „Wenn zwei Objekte gleich sind (wie von der isEqual:
Methode bestimmt), müssen sie denselben Hashwert haben.“ Derzeit implementiert hash
und isEqual:
verwendet NSObject die Identität (Adresse) des Objekts. Wenn Sie überschreiben isEqual:
, richten Sie die Möglichkeit von Objekten ein, die nicht identisch, aber gleich sind. Wenn Sie nicht auch überschreiben hash
, werden immer noch unterschiedliche Hashes angezeigt. Dies verstößt gegen die Anforderung, dass gleiche Objekte gleiche Hashes haben.
member:
wird der Container nur in diesem angezeigt Bucket (weshalb Sets beim Testen der Mitgliedschaft so viel schneller sind als Arrays und Wörterbücher beim Nachschlagen von Schlüsselwerten so viel schneller als parallele Arrays). Wenn das gesuchte Objekt den falschen Hash hat, sucht der Container im falschen Eimer und findet keine Übereinstimmung.
-[NSObject hash]
0 war. Das erklärt viel. = S
NSSet hat keine Methode objectAtIndex:
Versuchen Sie, allObjects aufzurufen, das ein NSArray aller Objekte zurückgibt.
Es ist möglich, filteredSetUsingPredicate zu verwenden, wenn Sie eine eindeutige Kennung zur Auswahl des gewünschten Objekts haben.
Erstellen Sie zuerst das Prädikat (vorausgesetzt, Ihre eindeutige ID im Objekt heißt "Bezeichner" und ist ein NSString):
NSPredicate *myPredicate = [NSPredicate predicateWithFormat:@"identifier == %@", identifier];
Wählen Sie dann das Objekt mit dem Prädikat aus:
NSObject *myChosenObject = [mySet filteredSetUsingPredicate:myPredicate].anyObject;
Für Swift3 und iOS10:
//your current set
let mySet : NSSet
//targetted index
let index : Int
//get object in set at index
let object = mySet.allObjects[index]
NSSet verwendet die Methode isEqual: (die Objekte, die Sie in diesen Satz einfügen, müssen zusätzlich die Hash-Methode überschreiben), um festzustellen, ob sich ein Objekt darin befindet.
Wenn Sie beispielsweise ein Datenmodell haben, das seine Eindeutigkeit durch einen ID-Wert definiert (sagen wir, die Eigenschaft lautet:
@property NSUInteger objectID;
dann würden Sie isEqual: as implementieren
- (BOOL)isEqual:(id)object
{
return (self.objectID == [object objectID]);
}
und Sie könnten Hash implementieren:
- (NSUInteger)hash
{
return self.objectID; // to be honest, I just do what Apple tells me to here
// because I've forgotten how Sets are implemented under the hood
}
Anschließend können Sie ein Objekt mit dieser ID abrufen (und prüfen, ob es sich im NSSet befindet) mit:
MyObject *testObject = [[MyObject alloc] init];
testObject.objectID = 5; // for example.
// I presume your object has more properties which you don't need to set here
// because it's objectID that defines uniqueness (see isEqual: above)
MyObject *existingObject = [mySet member: testObject];
// now you've either got it or existingObject is nil
Aber ja, der einzige Weg, etwas aus einem NSSet herauszuholen, besteht darin, das zu berücksichtigen, was seine Einzigartigkeit überhaupt definiert.
Ich habe nicht getestet, was schneller ist, aber ich vermeide die Verwendung von Aufzählungen, da dies linear sein könnte, während die Verwendung der member: -Methode viel schneller wäre. Dies ist einer der Gründe, die Verwendung von NSSet anstelle von NSArray zu bevorzugen.
for (id currentElement in mySet)
{
// ** some actions with currentElement
}
Meistens ist es Ihnen egal, ob Sie ein bestimmtes Objekt aus einem Set abrufen. Sie möchten testen, ob ein Satz ein Objekt enthält. Dafür sind Sets gut. Wenn Sie sehen möchten, ob sich ein Objekt in einer Sammlung befindet, sind Sätze viel schneller als Arrays.
Wenn Sie sich nicht darum kümmern, welches Objekt Sie erhalten, verwenden Sie das, -anyObject
das Ihnen nur ein Objekt aus dem Set gibt, z. B. Ihre Hand in eine Tasche stecken und etwas greifen.
Dog *aDog = [dogs anyObject]; // dogs is an NSSet of Dog objects
Wenn Sie sich für das Objekt interessieren, das Sie erhalten, verwenden -member
Sie, um das Objekt zurückzugeben, oder null, wenn es nicht im Set enthalten ist. Sie müssen das Objekt bereits haben, bevor Sie es aufrufen.
Dog *spot = [Dog dogWithName:@"Spot"];
// ...
Dog *aDog = [dogs member:spot]; // Returns the same object as above
Hier ist ein Code, den Sie in Xcode ausführen können, um mehr zu verstehen
NSString *one = @"One";
NSString *two = @"Two";
NSString *three = @"Three";
NSSet *set = [NSSet setWithObjects:one, two, three, nil];
// Can't use Objective-C literals to create a set.
// Incompatible pointer types initializing 'NSSet *' with an expression of type 'NSArray *'
// NSSet *set = @[one, two, three];
NSLog(@"Set: %@", set);
// Prints looking just like an array but is actually not in any order
//Set: {(
// One,
// Two,
// Three
// )}
// Get a random object
NSString *random = [set anyObject];
NSLog(@"Random: %@", random); // Random: One
// Iterate through objects. Again, although it prints in order, the order is a lie
for (NSString *aString in set) {
NSLog(@"A String: %@", aString);
}
// Get an array from the set
NSArray *array = [set allObjects];
NSLog(@"Array: %@", array);
// Check for an object
if ([set containsObject:two]) {
NSLog(@"Set contains two");
}
// Check whether a set contains an object and return that object if it does (nil if not)
NSString *aTwo = [set member:two];
if (aTwo) {
NSLog(@"Set contains: %@", aTwo);
}
[[nsSetObjects allObjects] objectAtIndex: anyInteger]