Si vous ne pouvez pas obtenir un objet avec objectAtIndex: à partir d'un NSSet, comment récupérer des objets?
Si vous ne pouvez pas obtenir un objet avec objectAtIndex: à partir d'un NSSet, comment récupérer des objets?
Réponses:
Il existe plusieurs cas d'utilisation pour un ensemble. Vous pouvez énumérer via (par exemple avec enumerateObjectsUsingBlock
ou NSFastEnumeration), appeler containsObject
pour tester l'appartenance, utiliser anyObject
pour obtenir un membre (non aléatoire) ou le convertir en un tableau (sans ordre particulier) avec allObjects
.
Un ensemble est approprié lorsque vous ne voulez pas de doublons, que vous ne vous souciez pas de la commande et que vous voulez des tests d'adhésion rapides.
member:
message à l'ensemble . S'il retourne nil
, l'ensemble ne contient pas un objet égal à celui que vous avez passé; s'il renvoie un pointeur d'objet, alors le pointeur qu'il renvoie est vers l'objet déjà dans l'ensemble. Les objets de l'ensemble doivent implémenter hash
et isEqual:
pour que cela soit utile.
hash
nécessaire de l'implémenter; cela irait beaucoup plus vite si vous faisiez cela.
hash
dans le protocole NSObject: «Si deux objets sont égaux (comme déterminé par la isEqual:
méthode), ils doivent avoir la même valeur de hachage.» Actuellement, les implémentations de NSObject hash
et isEqual:
utilisent l'identité (adresse) de l'objet. Si vous remplacez isEqual:
, vous configurez la possibilité d'objets qui ne sont pas identiques mais égaux - qui, si vous ne remplacez pas également hash
, auront toujours des hachages différents. Cela viole l'exigence selon laquelle les objets égaux ont des hachages égaux.
member:
, le conteneur ne recherchera que dans celui-là bucket (c'est pourquoi les ensembles sont tellement plus rapides que les tableaux lors des tests d'appartenance et les dictionnaires sont tellement plus rapides que les tableaux parallèles lors de la recherche clé-valeur). Si l'objet recherché a le mauvais hachage, le conteneur recherchera dans le mauvais compartiment et ne trouvera pas de correspondance.
-[NSObject hash]
était 0. Cela explique beaucoup de choses. = S
NSSet n'a pas de méthode objectAtIndex:
Essayez d'appeler allObjects qui renvoie un NSArray de tous les objets.
il est possible d'utiliser filteredSetUsingPredicate si vous avez une sorte d'identifiant unique pour sélectionner l'objet dont vous avez besoin.
Commencez par créer le prédicat (en supposant que votre identifiant unique dans l'objet s'appelle "identifiant" et qu'il s'agit d'une NSString):
NSPredicate *myPredicate = [NSPredicate predicateWithFormat:@"identifier == %@", identifier];
Et puis choisissez l'objet en utilisant le prédicat:
NSObject *myChosenObject = [mySet filteredSetUsingPredicate:myPredicate].anyObject;
Pour Swift3 et iOS10:
//your current set
let mySet : NSSet
//targetted index
let index : Int
//get object in set at index
let object = mySet.allObjects[index]
NSSet utilise la méthode isEqual: (que les objets que vous placez dans cet ensemble doivent remplacer, en outre, la méthode de hachage) pour déterminer si un objet se trouve à l'intérieur de celui-ci.
Ainsi, par exemple, si vous avez un modèle de données qui définit son unicité par une valeur d'id (disons que la propriété est:
@property NSUInteger objectID;
alors vous implémenteriez isEqual: as
- (BOOL)isEqual:(id)object
{
return (self.objectID == [object objectID]);
}
et vous pouvez implémenter le hachage:
- (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
}
Ensuite, vous pouvez obtenir un objet avec cet ID (ainsi que vérifier s'il est dans le NSSet) avec:
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
Mais oui, la seule façon d'obtenir quelque chose d'un NSSet est de considérer ce qui définit son unicité en premier lieu.
Je n'ai pas testé ce qui est le plus rapide, mais j'évite d'utiliser l'énumération car cela pourrait être linéaire alors que l'utilisation de la méthode member: serait beaucoup plus rapide. C'est l'une des raisons de préférer l'utilisation de NSSet au lieu de NSArray.
for (id currentElement in mySet)
{
// ** some actions with currentElement
}
La plupart du temps, vous ne vous souciez pas d'obtenir un objet particulier d'un ensemble. Vous vous souciez de tester pour voir si un ensemble contient un objet. C'est à cela que servent les décors. Lorsque vous voulez voir si un objet est dans une collection, les ensembles sont beaucoup plus rapides que les tableaux.
Si vous ne vous souciez pas de ce qui obtenez vous opposez, utilisez ce -anyObject
qui vous donne un seul objet de l'ensemble, comme mettre la main dans un sac et saisissant quelque chose.
Dog *aDog = [dogs anyObject]; // dogs is an NSSet of Dog objects
Si vous vous souciez de l'objet que vous obtenez, utilisez celui -member
qui vous rend l'objet, ou nul s'il n'est pas dans l'ensemble. Vous devez déjà disposer de l'objet avant de l'appeler.
Dog *spot = [Dog dogWithName:@"Spot"];
// ...
Dog *aDog = [dogs member:spot]; // Returns the same object as above
Voici un code que vous pouvez exécuter dans Xcode pour en savoir plus
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]