Хоча це питання давнє, речі не змінилися, прийнята відповідь невірна.
enumerateObjectsUsingBlock
API не був призначений , щоб замінити for-in
, але зовсім інший варіант використання:
- Це дозволяє застосовувати довільну, не локальну логіку. тобто вам не потрібно знати, що робить блок, щоб використовувати його в масиві.
- Одночасне перерахування для великих колекцій або важких обчислень (за допомогою
withOptions:
параметра)
Швидке перерахування for-in
все ще є ідіоматичним методом перерахунку колекції.
Швидке перерахування вигоди від стислості коду, читабельності та додаткових оптимізацій що робить його неприродно швидким. Швидше, ніж старий C-цикл!
Швидкий тест дозволяє зробити висновок, що в 2014 році на iOS 7, enumerateObjectsUsingBlock
стабільно на 700% повільніше, ніж при вході (на основі 1-мм ітерацій масиву 100 елементів).
Чи справді тут справді важливе питання?
Однозначно ні, за рідкісним винятком.
Сенс у тому, щоб продемонструвати, що користь від використання мало enumerateObjectsUsingBlock:
надмірноfor-in
без дійсно вагомих причин. Це не робить код більш читабельним ... або швидшим ... або безпечним для потоків. (ще одне поширене неправильне уявлення).
Вибір зводиться до особистих переваг. Для мене виграє ідіоматичний і читаний варіант. У цьому випадку це швидке використанняfor-in
.
Орієнтир:
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);
Результати:
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