How to enumerate an arbitrary set that conforms to NSFastEnumeration

468 views Asked by At

I am trying to enumerate over a bunch of objects which, depending on the situation, may be either an NSArray or an NSOrderedSet. Since both conform to NSFastEnumeration, I would expect this to work:

id<NSFastEnumeration> enumerableSet =
(test) ?
[NSArray arrayWithObjects:@"one", @"two", @"three", nil] :
[NSOrderedSet orderedSetWithObjects:@"one", @"two", @"three", nil];

NSEnumerator *e = [enumerableSet objectEnumerator];

However, I get the following compiler error:

No known instance method for selector 'objectEnumerator'.

I suspect there is some syntax error here, I haven't worked much with the id construct before. I could convert one or both of the sets to a common class, but if possible I'd like to understand better what's going on here.

3

There are 3 answers

0
lnafziger On BEST ANSWER

objectEnumerator is not declared in the NSFastEnumeration protocol, therefore using [enumerableSet objectEnumerator]; will not work because you are working with type `id' which doesn't define that method.

Since objectEnumerator is declared as a property of a NSArray and a NSSet (with no common super class), you will need to set the enumerator from a variable which knows that it is an array/set. I.e.:

NSEnumerator *e = 
(test) ?
[[NSArray arrayWithObjects:@"one", @"two", @"three", nil] objectEnumerator]:
[[NSOrderedSet orderedSetWithObjects:@"one", @"two", @"three", nil] objectEnumerator];
0
Sasha On

Ok, never mind. I just found my answer. objectEnumerator is not part of the protocol - so although both NSArray and NSOrderedSet have an objectEnumerator message, I can't use it this way. Instead, this seems to work:

NSEnumerator *e =
(test) ?
[[NSArray arrayWithObjects:@"one", @"two", @"three", nil] objectEnumerator]:
[[NSOrderedSet orderedSetWithObjects:@"one", @"two", @"three", nil] objectEnumerator];
0
Douglas Hill On

You have objects that conform to the NSFastEnumeration protocol, but you are trying to use ‘slow’ enumeration with NSEnumerator. Instead, use fast enumeration:

id<NSFastEnumeration> enumerableSet =
(test) ?
[NSArray arrayWithObjects:@"one", @"two", @"three", nil] :
[NSOrderedSet orderedSetWithObjects:@"one", @"two", @"three", nil];

for (id object in enumerableSet) {
    // ...
}

See Fast Enumeration Makes It Easy to Enumerate a Collection in Apple’s Programming with Objective-C.

I recommend using fast enumeration instead of NSEnumerator wherever possible; fast enumeration is clearer, more concise and faster.