Si vous ne pouvez pas obtenir un objet avec objectAtIndex: à partir d'un NSSet, comment récupérer des objets?
Il existe plusieurs cas d'utilisation pour un ensemble. Vous pouvez énumérer (par exemple, avec enumerateObjectsUsingBlock
ou NSFastEnumeration), appeler containsObject
pour tester votre appartenance, utilisez anyObject
pour obtenir un membre (non aléatoire) ou convertissez-le en un tableau sans ordre particulier) avec allObjects
.
Un ensemble est approprié lorsque vous ne voulez pas de doublons, ne vous souciez pas de la commande et que vous souhaitez tester rapidement les membres.
NSSet n'a pas de méthode objectAtIndex:
Essayez d'appeler allObjects qui renvoie un tableau NSArray de tous les objets.
filterSetUsingPredicate est possible si vous avez un 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'agisse d'une chaîne NSString):
NSPredicate *myPredicate = [NSPredicate predicateWithFormat:@"identifier == %@", identifier];
Et puis choisissez l'objet en utilisant le prédicat:
NSObject *myChosenObject = [mySet filteredSetUsingPredicate:myPredicate].anyObject;
NSArray *myArray = [myNSSet allObjects];
MyObject *object = [myArray objectAtIndex:(NSUInteger *)]
remplacez NSUInteger par l’index de l’objet souhaité.
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 doit également remplacer la méthode de hachage) pour déterminer si un objet se trouve à l'intérieur.
Ainsi, par exemple, si vous avez un modèle de données qui définit son unicité par une valeur id (par exemple, 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 hash:
- (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 (et vérifier s'il se trouve 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, le seul moyen d’obtenir quelque chose d’un NSSet est de considérer ce qui en définit le caractère unique.
Je n'ai pas testé ce qui est plus rapide, mais j'évite d'utiliser une énumération, car elle peut être linéaire, alors que l'utilisation de la méthode member: serait beaucoup plus rapide. C'est l'une des raisons pour lesquelles préférer l'utilisation de NSSet à la place de NSArray.
for (id currentElement in mySet)
{
// ** some actions with currentElement
}
La plupart du temps, vous ne vous souciez pas de récupérer un objet particulier d'un ensemble. Vous vous souciez de tester pour voir si un ensemble contient un objet. C'est pour ça que les décors sont bons. 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 quel objet vous obtenez, utilisez -anyObject
qui vous donne juste un objet de l'ensemble, comme mettre votre main dans un sac et attraper quelque chose.
Dog *aDog = [dogs anyObject]; // dogs is an NSSet of Dog objects
Si vous vous souciez de quel objet vous obtenez, utilisez -member
qui vous rend l'objet, ou nil si ce n'est pas dans l'ensemble. Vous devez déjà avoir 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 mieux comprendre.
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);
}