Qual é o argumento BOOL * stop para enumerateObjectsUsingBlock: usado para?

87

Tenho usado enumerateObjectsUsingBlock:muito ultimamente para minhas necessidades de enumeração rápida e estou tendo dificuldade em entender o uso de BOOL *stopno bloco de enumeração.

Os NSArrayestados de referência da classe

stop: Uma referência a um valor booleano. O bloco pode definir o valor YESpara interromper o processamento adicional da matriz. O stopargumento é um argumento exclusivo. Você só deve definir esse booleano como YESdentro do bloco.

Então, é claro, posso adicionar o seguinte em meu bloco para interromper a enumeração:

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

Pelo que pude perceber, não definir explicitamente *stopcomo YESnão tem efeitos colaterais negativos. A enumeração parece parar automaticamente no final da matriz. Então, usar é *stoprealmente necessário em um bloco?

Mick MacCallum
fonte

Respostas:

156

O stopargumento para o Bloco permite que você pare a enumeração prematuramente . É o equivalente a de breakum forloop normal . Você pode ignorá-lo se quiser percorrer todos os objetos do array.

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];
}];

Esse é um parâmetro de saída porque é uma referência a uma variável do escopo de chamada. Ele precisa ser definido dentro do seu Bloco, mas lido dentro dele enumerateObjectsUsingBlock:, da mesma forma que NSErrors são comumente passados ​​de volta para o seu código a partir de chamadas do framework.

- (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;
        }
    }
}
jscs
fonte
21
Observe que o stopsinalizador é consultivo; a enumeração pode continuar por algum número indefinido de iterações no caso simultâneo, por exemplo. Ou seja, você não deve definir uma __blockvariável incondicionalmente em cada passagem pela enumeração e esperar que seja o "último" valor ao usar stoppara encerrar antecipadamente. Você deve sempre acoplar o "não, use este objeto" com a configuração stop = YES;.
bbum de
@bbum, você pode esclarecer se o comportamento contínuo se aplica apenas à enumeração simultânea? Embora seja perfeitamente compreensível nesse caso, não está documentado e seria uma mordida na bunda bastante surpreendente para enumeração "serial".
jscs
4
<rdar: // problem / 15015199> agora pede esclarecimentos, pois a documentação não diz nenhuma das formas e deveria.
bbum de