Chociaż to pytanie jest stare, nic się nie zmieniło, przyjęta odpowiedź jest nieprawidłowa.
enumerateObjectsUsingBlock
API nie miało zastępują for-in
, ale na zupełnie innym przypadku użycia:
- Pozwala na zastosowanie dowolnej, nielokalnej logiki. tj. nie musisz wiedzieć, co robi blok, aby użyć go na tablicy.
- Równoczesne wyliczanie dla dużych kolekcji lub ciężkich obliczeń (przy użyciu
withOptions:
parametru)
Fast Enumeration with for-in
jest nadal idiomatyczną metodą wyliczania kolekcji.
Fast Enumeration korzysta ze zwięzłości kodu, czytelności i dodatkowych optymalizacji, które sprawiają, że jest nienaturalnie szybki. Szybszy niż stara pętla for w C!
Szybki test stwierdza, że w roku 2014 na iOS 7 enumerateObjectsUsingBlock
jest konsekwentnie o 700% wolniejszy niż for-in (na podstawie 1 mm iteracji tablicy 100 elementów).
Czy wydajność jest tutaj praktycznym problemem?
Zdecydowanie nie, z rzadkimi wyjątkami.
Chodzi o to, aby wykazać, że istnieje niewiele korzyści przy użyciu enumerateObjectsUsingBlock:
ponad for-in
bez naprawdę dobrego powodu. Nie czyni kodu bardziej czytelnym ... ani szybszym ... ani bezpiecznym wątkowo. (kolejne powszechne nieporozumienie).
Wybór sprowadza się do osobistych preferencji. U mnie wygrywa opcja idiomatyczna i czytelna. W tym przypadku jest to szybkie wyliczanie przy użyciu for-in
.
Reper:
NSMutableArray *arr = [NSMutableArray array];
for (int i = 0; i < 100; i++) {
arr[i] = [NSString stringWithFormat:@"%d", i];
}
int i;
__block NSUInteger length;
i = 1000 * 1000;
uint64_t a1 = mach_absolute_time();
while (--i > 0) {
for (NSString *s in arr) {
length = s.length;
}
}
NSLog(@"For-in %llu", mach_absolute_time()-a1);
i = 1000 * 1000;
uint64_t b1 = mach_absolute_time();
while (--i > 0) {
[arr enumerateObjectsUsingBlock:^(NSString *s, NSUInteger idx, BOOL *stop) {
length = s.length;
}];
}
NSLog(@"Enum %llu", mach_absolute_time()-b1);
Wyniki:
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