Задача c «для каждого» (быстрое перечисление) - оценка коллекции? - PullRequest
11 голосов
/ 07 октября 2010

Из экспериментов видно, что выражение коллекции вычисляется только один раз. Рассмотрим этот пример:

static NSArray *a;

- (NSArray *)fcn
{
    if (a == nil)
        a = [NSArray arrayWithObjects:@"one", @"two", @"three", nil];
    NSLog(@"called");
    return a;
}

...

for (NSString *s in [self fcn])
    NSLog(@"%@", s);

Вывод:

2010-10-07 07:37:31.419 WidePhotoViewer Lite[23694:207] called
2010-10-07 07:37:31.420 WidePhotoViewer Lite[23694:207] one
2010-10-07 07:37:31.425 WidePhotoViewer Lite[23694:207] two
2010-10-07 07:37:31.425 WidePhotoViewer Lite[23694:207] three

указывает, что [self fcn] вызывается только один раз.

Может ли кто-нибудь подтвердить, что это указанное (а не просто наблюдаемое) поведение?

То, что я имею в виду, делает что-то вроде этого:

for (UIView *v in [innerView subviews]) {

вместо этого:

NSArray *vs = [innerView subviews];
for (UIView *v in vs) {

Мысли

Ответы [ 4 ]

13 голосов
/ 07 октября 2010

Этот вид цикла for называется «быстрым перечислением» (посмотрите на объект NSFastEnumeration). В документации Apple говорится, что в выражении «для obj в выражении» выражение возвращает объект, соответствующий протоколу NSFastEnumeration, поэтому я предполагаю, что это правильное поведение: функция вызывается один раз, итератор создается один раз и используется в цикле.

7 голосов
/ 07 октября 2010

На практике collection оценивается только один раз, например, вы можете проверить источник лязга. Когда документация не говорит достаточно точно, вам нужно доверять реализации.

Да, думаю, Apple должна уточнить документацию. Пожалуйста, отправьте сообщение об ошибке, Марк!

Один педантичный способ получить это - прочитать поле официальной документации, которое можно найти здесь . Утверждается, что

перечислитель имеет защиту от мутаций, поэтому при попытке изменить коллекцию во время перечисления возникает исключение. Поскольку изменение объекта во время итерации запрещено, вы можете выполнять несколько перечислений одновременно.

Итак, коллекция, которую вы перебираете, все равно не может измениться. Он не говорит, оценивает ли он collection в

for(id obj in collection) { ... } 

один или два раза, результирующий объект не может измениться.

3 голосов
/ 07 октября 2010

Здравый смысл подсказывает, что так и будет. Но поскольку это прямо не указано в документации по быстрому перечислению, почему бы вам не взглянуть на сам протокол:

http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/NSFastEnumeration_protocol/Reference/NSFastEnumeration.html

Этот протокол не предоставляет такие методы, как nextObject, objectAtIndex или что-то в этом роде, но вместо этого запрашивает массив объектов C, который затем повторяется.

Несмотря на наличие явных указаний, ни один документ не гарантирует, что выражение вычисляется только один раз.

0 голосов
/ 07 октября 2010

Это часть поведения быстрого перечисления. Для некоторых глубоких знаний о реализации быстрого перечисления проверьте этот пост в блоге NSBlog: Реализация быстрого перечисления.

...