Для чего используется аргумент BOOL * stop для enumerateObjectsUsingBlock:?

87

В последнее время я много использую enumerateObjectsUsingBlock:для своих потребностей в быстром перечислении, и мне трудно понять использование BOOL *stopв блоке перечисления.

В NSArrayссылке на класс говорится

stop: Ссылка на логическое значение. Блок может установить значение, YESчтобы остановить дальнейшую обработку массива. stopАргумент является из-единственного аргумента. Вы должны устанавливать это логическое значение только в YESпределах блока.

Итак, конечно, я могу добавить в свой блок следующее, чтобы остановить перечисление:

if (idx == [myArray indexOfObject:[myArray lastObject]]) {
    *stop = YES;
}

Из того, что я был в состоянии сказать, явно не установка *stopна YESне имеет каких - либо негативных побочных эффектов. Похоже, что перечисление автоматически останавливается в конце массива. Так *stopдействительно ли необходимо использовать в блоке?

Мик МакКаллум
источник

Ответы:

156

stopАргумент блока позволяет остановить перечисление преждевременно . Это эквивалент breakобычного forцикла. Вы можете игнорировать его, если хотите просмотреть каждый объект в массиве.

for( id obj in arr ){
    if( [obj isContagious] ){
        break;    // Stop enumerating
    }

    if( ![obj isKindOfClass:[Perefrigia class]] ){
        continue;    // Skip this object
    }

    [obj immanetizeTheEschaton];
}

[arr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    if( [obj isContagious] ){
        *stop = YES;    // Stop enumerating
        return;
    }

    if( ![obj isKindOfClass:[Perefrigia class]] ){
        return;    // Skip this object
    }

    [obj immanentizeTheEschaton];
}];

Это выходной параметр, потому что это ссылка на переменную из вызывающей области. Его нужно установить внутри вашего блока, но читать внутри него enumerateObjectsUsingBlock:, точно так же, как NSErrors обычно передаются обратно в ваш код из вызовов фреймворка.

- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block {
    // N.B: This is probably not how this method is actually implemented!
    // It is just to demonstrate how the out parameter operates!

    NSUInteger idx = 0;
    for( id obj in self ){

        BOOL stop = NO;

        block(obj, idx++, &stop);

        if( stop ){
            break;
        }
    }
}
ао
источник
21
Обратите внимание, что stopфлаг носит рекомендательный характер; Перечисление может продолжаться, например, в течение некоторого неопределенного количества итераций в параллельном случае. Т.е. вы не должны __blockбезоговорочно устанавливать переменную при каждом проходе по перечислению и ожидать, что она будет «последним» значением при использовании stopдля раннего завершения. Вы всегда должны связывать «нет, используйте этот объект» с настройкой stop = YES;.
bbum
@bbum, не могли бы вы уточнить, применяется ли продолжающееся поведение только к параллельному перечислению? Хотя в этом случае это вполне понятно, но это не задокументировано и было бы довольно неожиданным укусом для "последовательного" перечисления.
jscs
4
<rdar: // проблема / 15015199> теперь требует разъяснений, поскольку в документации не сказано иного, и должно.
bbum