If you can't get an object with objectAtIndex: from an NSSet then how do you retrieve objects?
-
1`[[nsSetObjects allObjects] objectAtIndex: anyInteger]` – Mubeen Qazi Nov 21 '19 at 07:50
8 Answers
There are several use cases for a set. You could enumerate through (e.g. with enumerateObjectsUsingBlock
or NSFastEnumeration), call containsObject
to test for membership, use anyObject
to get a member (not random), or convert it to an array (in no particular order) with allObjects
.
A set is appropriate when you don't want duplicates, don't care about order, and want fast membership testing.

- 278,309
- 50
- 514
- 539
-
7You can also look up a known object by a potential duplicate by sending the set a `member:` message. If it returns `nil`, the set does not contain an object equal to the one you passed; if it returns an object pointer, then the pointer it returns is to the object already in the set. The objects in the set must implement `hash` and `isEqual:` for this to be useful. – Peter Hosey Sep 30 '10 at 04:44
-
@PeterHosey I don't think `hash` _needs_ to be implemented; it would just go a lot faster if you did do that. – fumoboy007 Aug 11 '13 at 22:17
-
2@fumoboy007: For storage in a set or use as a key in a dictionary, yes it does. From the documentation of `hash` in the NSObject protocol: “If two objects are equal (as determined by the `isEqual:` method), they must have the same hash value.” Currently, NSObject's implementations of `hash` and `isEqual:` use the object's identity (address). If you override `isEqual:`, you're setting up the possibility of objects that are not identical but are equal—which, if you don't also override `hash`, will still have different hashes. That violates the requirement that equal objects have equal hashes. – Peter Hosey Aug 11 '13 at 23:23
-
1@fumoboy007: Consider how a hash table works: The container has an array of some number of buckets, and uses each incoming object's hash to determine which bucket that object should be in. For lookups such as `member:`, the container will only look in that one bucket (which is why sets are so much faster than arrays at membership testing and dictionaries are so much faster than parallel arrays at key-value lookup). If the object being sought has the wrong hash, then the container will look in the wrong bucket, and not find a match. – Peter Hosey Aug 11 '13 at 23:28
-
@PeterHosey Oops…I mistakenly thought that the default implementation of `-[NSObject hash]` was 0. That explains a lot. =S – fumoboy007 Aug 12 '13 at 23:24
NSSet doesn't have a method objectAtIndex:
Try calling allObjects which returns an NSArray of all the objects.

- 2,682
- 2
- 17
- 20
-
do you have any idea if the array returned is ordered? in other words, if im adding objects to the set using "setByAddingObject", and i used "allObjects", are? the elements in the array ordered in the order I added the objects? – iosMentalist Jul 03 '12 at 07:40
-
just sort the resulting array with an NSSortPredicate and you'll be fine – Jason Mar 08 '13 at 05:00
-
If you're only interested in one specific object, better use the filteredSetUsingPredicate approach. – akw Oct 05 '13 at 14:41
it is possible to use filteredSetUsingPredicate if you have some kind of unique identifier to select the object you need.
First create the predicate (assuming your unique id in the object is called "identifier" and it is an NSString):
NSPredicate *myPredicate = [NSPredicate predicateWithFormat:@"identifier == %@", identifier];
And then choose the object using the predicate:
NSObject *myChosenObject = [mySet filteredSetUsingPredicate:myPredicate].anyObject;

- 4,267
- 1
- 40
- 45
NSArray *myArray = [myNSSet allObjects];
MyObject *object = [myArray objectAtIndex:(NSUInteger *)]
replace NSUInteger with the index of your desired object.

- 229
- 3
- 10
For Swift3 & iOS10 :
//your current set
let mySet : NSSet
//targetted index
let index : Int
//get object in set at index
let object = mySet.allObjects[index]

- 16,507
- 12
- 93
- 99
NSSet uses the method isEqual: (which the objects you put into that set must override, in addition, the hash method) to determine if an object is inside of it.
So, for example if you have a data model that defines its uniqueness by an id value (say the property is:
@property NSUInteger objectID;
then you'd implement isEqual: as
- (BOOL)isEqual:(id)object
{
return (self.objectID == [object objectID]);
}
and you could implement 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
}
Then, you can get an object with that ID (as well as check for whether it's in the NSSet) with:
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
But yeah, the only way to get something out of a NSSet is by considering that which defines its uniqueness in the first place.
I haven't tested what's faster, but I avoid using enumeration because that might be linear whereas using the member: method would be much faster. That's one of the reasons to prefer the use of NSSet instead of NSArray.

- 2,745
- 2
- 35
- 49
for (id currentElement in mySet)
{
// ** some actions with currentElement
}

- 360
- 3
- 8
Most of the time you don't care about getting one particular object from a set. You care about testing to see if a set contains an object. That's what sets are good for. When you want to see if an object is in a collection sets are much faster than arrays.
If you don't care about which object you get, use -anyObject
which just gives you one object from the set, like putting your hand in a bag and grabbing something.
Dog *aDog = [dogs anyObject]; // dogs is an NSSet of Dog objects
If you care about what object you get, use -member
which gives you back the object, or nil if it's not in the set. You need to already have the object before you call it.
Dog *spot = [Dog dogWithName:@"Spot"];
// ...
Dog *aDog = [dogs member:spot]; // Returns the same object as above
Here's some code you can run in Xcode to understand more
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);
}

- 112,709
- 45
- 203
- 241