150 votes

Quand utiliser enumerateObjectsUsingBlock contre pour

Outre les différences évidentes:

  • Utilisez enumerateObjectsUsingBlock lorsque vous avez besoin à la fois de l'index et de l'objet
  • N'utilisez pas enumerateObjectsUsingBlock lorsque vous devez modifier des variables locales (je me suis trompé à ce sujet, voir la réponse de bbum)

Est-ce que enumerateObjectsUsingBlock généralement considéré comme meilleur ou pire lorsque for (id obj in myArray) fonctionneraient également? Quels sont les avantages / inconvénients (par exemple, est-il plus ou moins performant)?

347voto

bbum Points 124887

En fin de compte, utiliser n'importe quel modèle que vous souhaitez utiliser, puis vient plus naturellement dans le contexte.

Alors qu' for(... in ...) est très pratique et syntaxiquement bref, enumerateObjectsUsingBlock: a un certain nombre de caractéristiques qui peuvent ou peuvent ne pas s'avérer intéressant:

  • enumerateObjectsUsingBlock: sera aussi rapide ou plus rapide que rapide énumération (for(... in ...) utilise l' NSFastEnumeration pour la mise en œuvre de l'énumération). Rapide énumération nécessite la traduction à partir d'une représentation interne de la représentation pour une rapide énumération. Il existe une surcharge qui y sont. En fonction de bloc énumération permet à la classe de collection pour énumérer le contenu aussi vite que le plus rapide de la traversée de la native du format de stockage. Probablement pas pertinent pour les tableaux, mais il peut y avoir une énorme différence pour les dictionnaires.

  • "N'utilisez pas enumerateObjectsUsingBlock lorsque vous avez besoin de modifier les variables locales" - pas vrai; vous pouvez déclarer vos locaux comme __block et ils vont avoir les droits d'écriture dans le bloc.

  • enumerateObjectsWithOptions:usingBlock: prend en charge simultanée ou d'inverser l'énumération.

  • à l'aide de dictionnaires, de bloquer l'énumération est la seule façon de récupérer la clé et la valeur simultanément.

Personnellement, j'utilise" enumerateObjectsUsingBlock: plus souvent qu' for (... in ...), mais - encore une fois - un choix personnel.

81voto

Chuck Points 138930

Pour la simple énumération, simplement à l'aide de fast énumération (c'est à dire un for…in… boucle) est le plus idiomatique option. La méthode pourrait être légèrement plus rapide, mais qui n'a pas beaucoup d'importance dans la plupart des cas - rares sont les programmes qui sont lié au PROCESSEUR, et même alors, il est rare que la boucle elle-même plutôt que le calcul à l'intérieur sera un goulot d'étranglement.

Une simple boucle lit aussi plus clairement. Voici le code des deux versions:

for (id x in y){
}

[y enumerateObjectsUsingBlock:^(id x, NSUInteger index, BOOL *stop){
}];

Même si vous ajouter une variable à la piste de l'index, la boucle est plus facile à lire.

Ainsi, lorsque vous devez utiliser enumerateObjectsUsingBlock:? Lorsque vous stockez un bloc à exécuter plus tard, ou dans de multiples endroits. C'est bon pour quand vous êtes en fait en utilisant un bloc, comme un premier de la classe de fonction plutôt qu'une exagérés de remplacement pour un corps de boucle.

42voto

adam kaplan Points 192

Bien que cette question est ancienne et les choses ont peut être changé, l'on a accepté la réponse est incorrecte.

La plus récente, enumerateObjectsUsingBlock n'était pas destinée à remplacer pour. La méthode réellement ajoute de nouvelles, différentes fonctionnalités:

  • À l'aide de blocs d'énumérer un tableau permet une mise en œuvre à l'utilisation arbitraire de la logique (les blocs générés dans un autre endroit que celui qu'il est appliqué)
  • Simultanées d'énumération pour les plus grandes collections lourds ou de calcul (à l'aide de la withOptions:)

Pour-en sur l'autre main est toujours le idiomatiques méthode de l'énumération d'une collection. Il bénéficie de la brièveté de code, de la lisibilité et probablement supplémentaires optimisations du compilateur.

Un test rapide en conclut que, dans l'année 2014 sur iOS 7, enumerateObjectsUsingBlock est systématiquement 700% plus lent que pour (basé sur 1mm d'itérations de 100 élément de tableau).

La performance est un réel problème ici?

Certainement pas, à de rares exceptions près.

Le point est de démontrer qu'il existe peu ou pas d'avantages à l'aide d' enumerateObjectsUsingBlock de plus pour les sans une bonne raison. Il ne veut pas rendre le code plus lisible... ou plus... ou le fil de la sécurité (une autre idée fausse très répandue).

Le choix se résume à la préférence personnelle. Comme 7 ans de iOS ingénieur qui a conduit iOS équipes de la construction d'un certains de la plus célèbre des applications iOS, avec des dizaines de millions d'utilisateurs, mon conseil est d'utiliser le plus simple et le plus idiomatique option: dans ce cas, Rapide Énumération utilisant pour.

Le rapide test de code:

NSMutableArray *arr = [NSMutableArray array];
for (int i = 0; i < 100; i++) {
    arr[i] = [NSString stringWithFormat:@"%d", i];
}
__block int i;
__block int length;

uint64_t a1 = mach_absolute_time();
i = 1000 * 1000;
while (--i > 0) {
    for (NSString *s in arr) {
        length = s.length;
    }
}
NSLog(@"For-in %llu", mach_absolute_time()-a1);

uint64_t b1 = mach_absolute_time();
i = 1000 * 1000;
while (--i > 0) {
    [arr enumerateObjectsUsingBlock:^(NSString *s, NSUInteger idx, BOOL *stop) {
        length = s.length;
    }];
}
NSLog(@"Enum %llu", mach_absolute_time()-b1);

Résultats:

2014-06-11 14:37:47.717 Test[57483:60b] For-in 1087754062
2014-06-11 14:37:55.492 Test[57483:60b] Enum   7775447746

23voto

LearnCocos2D Points 43044

Pour répondre à la question sur les performances, j'ai fait quelques tests à l'aide de mon test de performance du projet. Je voulais savoir laquelle des trois options pour l'envoi d'un message à tous les objets dans un tableau est le plus rapide.

Les options sont les suivantes:

1) makeObjectsPerformSelector

[arr makeObjectsPerformSelector:@selector(_stubMethod)];

2) rapide énumération et régulière message envoyer

for (id item in arr)
{
    [item _stubMethod];
}

3) enumerateObjectsUsingBlock les message envoyer

[arr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) 
 {
     [obj _stubMethod];
 }];

Il s'avère que makeObjectsPerformSelector était le plus lent, et de loin. Il a fallu deux fois plus long que rapide énumération. Et enumerateObjectsUsingBlock a été le plus rapide, il était d'environ 15 à 20% plus rapide que rapide itération.

Donc, si vous êtes très préoccupé par la meilleure performance possible, utilisez enumerateObjectsUsingBlock. Mais gardez à l'esprit que, dans certains cas, le temps qu'il faut pour énumérer une collection est rien en comparaison du temps nécessaire pour exécuter le code que vous voulez chaque objet à exécuter.

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