14 votes

Cocoa NSArray/NSSet: -makeObjectsPerformSelector: contre l'énumération rapide

Je veux effectuer la même action sur plusieurs objets stockés dans un NSSet.

Ma première tentative a consisté à utiliser une énumération rapide :

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

qui fonctionne assez bien. Ensuite, j'ai pensé à :

[mySetOfObjects makeObjectsPerformSelector:@selector(action)];

Et maintenant, je ne sais pas quel est le meilleur choix. Autant que je comprenne, les deux solutions sont équivalentes. Mais y a-t-il des arguments pour préférer une solution à l'autre?

22voto

e.James Points 51680

Je soutiendrais l'utilisation de makeObjectsPerformSelector, car cela permet à l'objet NSSet de gérer son propre indexation, bouclage et envoi de messages. Les personnes qui ont écrit le code NSSet sont les plus susceptibles de savoir la meilleure façon de mettre en œuvre cette boucle particulière.

Au pire, ils implémenteraient simplement la même boucle exacte, et tout ce que vous gagnez est un code légèrement plus propre (pas besoin de la boucle d'encapsulation). Au mieux, ils ont apporté des optimisations internes et le code fonctionnera en réalité plus rapidement.

Le sujet est brièvement mentionné dans le document Code Speed Performance d'Apple, dans la section intitulée "Déroulement de boucles".

Si vous êtes préoccupé par les performances, la meilleure chose à faire est de mettre en place un programme rapide qui effectue un sélecteur sur les objets dans un ensemble. Faites-le tourner plusieurs millions de fois, et mesurez la différence entre les deux cas différents.

7voto

daveMac Points 889

Je me suis également posé cette question. Je trouve dans la documentation Apple "Sujets de programmation des collections" sous "Sets: Collections non ordonnées d'objets" ce qui suit:

La méthode NSSet objectEnumerator vous permet de parcourir les éléments de l'ensemble un par un. Et les méthodes makeObjectsPerformSelector: et makeObjectsPerformSelector:withObject: permettent d'envoyer des messages aux objets individuels de l'ensemble. Dans la plupart des cas, l'énumération rapide doit être utilisée car elle est plus rapide et plus flexible que d'utiliser un NSEnumerator ou la méthode makeObjectsPerformSelector:. Pour en savoir plus sur l'énumération, voir "Énumération: Parcours des éléments d'une collection".

Cela me conduit à croire que l'énumération rapide est toujours le moyen le plus efficace pour cette application.

4voto

Tom Andersen Points 3523

Je ne voudrais pas utiliser makeObjectsPerformSelector pour la simple raison que c'est le genre d'appel que l'on ne voit pas si souvent. Voici pourquoi par exemple - j'ai besoin d'ajouter du code de débogage pendant l'énumération de tableau, et vous ne pouvez vraiment pas le faire avec makeObjectsPerformSelector à moins de modifier le fonctionnement du code en mode Release, ce qui est vraiment à proscrire.

for (id item in mySetOfObjects)
{
    #if MY_DEBUG_BUILD
    if ([item isAllMessedUp])
        NSLog(@"nous avons trouvé ce fichu bug qui nous hante"); 
    #endif

    [item action];
}

--Tom

2voto

Marc Charbonneau Points 30464

makeObjectsPerformSelector: pourrait être légèrement plus rapide, mais je doute qu'il y ait une différence pratique 99% du temps. C'est un peu plus concis et lisible, cependant, je l'utiliserais pour cette raison.

1voto

Mason Cloud Points 465

Si la vitesse pure est la seule préoccupation (c'est-à-dire que vous créez un moteur de rendu où chaque petit cycle CPU compte), le moyen le plus rapide de parcourir n'importe lequel des objets NSCollection (à partir d'iOS 5.0 ~ 6.0) est les différentes méthodes "enumerateObjectsUsingBlock". Je ne sais pas pourquoi, mais j'ai testé et il semble que ce soit le cas...

J'ai écrit un petit test créant des collections de centaines de milliers d'objets ayant chacun une méthode qui fait la somme d'un tableau simple d'entiers. Chacune de ces collections a été forcée de réaliser les différents types d'itération (boucle for, énumération rapide, makeObjectsPerformSelector et enumerateObjectsUsingBlock) des millions de fois, et dans presque tous les cas, les méthodes "enumerateObjectsUsingBlock" ont largement remporté les tests.

La seule fois où cela n'était pas vrai, c'était lorsque la mémoire a commencé à se remplir (lorsque j'ai commencé à l'exécuter avec des millions d'objets), après quoi il a commencé à perdre face à "makeObjectsPerformSelector".

Je suis désolé de ne pas avoir pris une capture d'écran du code, mais c'est un test très simple à réaliser, je vous recommande vivement de l'essayer et de voir par vous-même. :)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X