views:

1534

answers:

3

I want to perform the same action over several objects stored in a NSSet.

My first attempt was using a fast enumeration:

for (id item in mySetOfObjects)
    [item action];

which works pretty fine. Then I thought of:

[mySetOfObjects makeObjectsPerformSelector:@selector(action)];

And now, I don't know what is the best choice. As far as I understand, the two solutions are equivalent. But are there arguments for preferring one solution over the other?

+10  A: 

I would argue for using makeObjectsPerformSelector, since it allows the NSSet object to take care of its own indexing, looping and message dispatching. The people who wrote the NSSet code are most likely to know the best way to implement that particular loop.

At worst, they would simply implement the exact same loop, and all you gain is slightly cleaner code (no need for the enclosing loop). At best, they made some internal optimizations and the code will actually run faster.

The topic is briefly mentioned in Apple's Code Speed Performance document, in the section titled "Unrolling Loops".

If you're concerned about performance, the best thing to do is set up a quick program which performs some selector on the objects in a set. Have it run several million times, and time the difference between the two different cases.

e.James
Thank you for the link, I didn't know this document! As you say, the section "Unrolling loops" clearly states that Cocoa developers have made internal optimizations with -makeObjectsPerformSelector:
mouviciel
My pleasure. There's some interesting stuff in there.
e.James
+2  A: 

makeObjectsPerformSelector: might be slightly faster, but I doubt there's going to be any practical difference 99% of the time. It is a bit more concise and readable though, I would use it for that reason.

Marc Charbonneau
+1  A: 

I would not use makeObjectsPerformSelector for the simple reason that it is the kind of call that you don't see all that often. Here is why for example - I need to add debugging code as the array is enumerated, and you really can't do that with makeObjectsPerformSelector unless you change how the code works in Release mode which is a real no no.

for (id item in mySetOfObjects)
{
    #if MY_DEBUG_BUILD
    if ([item isAllMessedUp])
        NSLog(@"we found that wily bug that has been haunting us"); 
    #endif

    [item action];
}

--Tom

Tom Andersen