¿Para qué se utiliza el argumento BOOL * stop para enumerateObjectsUsingBlock:?

87

enumerateObjectsUsingBlock:Últimamente he estado usando mucho para mis necesidades de enumeración rápida y me cuesta entender el uso de BOOL *stopen el bloque de enumeración.

Los NSArrayestados de referencia de clase

stop: Una referencia a un valor booleano. El bloque puede establecer el valor en YESpara detener el procesamiento posterior de la matriz. El stopargumento es un argumento exclusivo. Solo debe establecer este booleano YESdentro del bloque.

Entonces, por supuesto, puedo agregar lo siguiente en mi bloque para detener la enumeración:

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

Por lo que he sido capaz de decir, no explícitamente el establecimiento *stopa YESno tiene ningún efecto secundario negativo. La enumeración parece detenerse automáticamente al final de la matriz. Entonces, ¿es *stoprealmente necesario usar en un bloque?

Mick MacCallum
fuente

Respuestas:

156

El stopargumento del Bloque le permite detener la enumeración antes de tiempo . Es el equivalente de breakun forbucle normal . Puede ignorarlo si desea revisar todos los objetos de la matriz.

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

Ese es un parámetro de salida porque es una referencia a una variable del ámbito de llamada. Debe configurarse dentro de su Bloque, pero leerse dentro de él enumerateObjectsUsingBlock:, de la misma manera que NSErrorlos correos electrónicos se pasan comúnmente a su código desde las llamadas al marco.

- (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
fuente
21
Tenga en cuenta que la stopbandera es un aviso; la enumeración puede continuar durante un número indefinido de iteraciones en el caso concurrente, por ejemplo. Es decir, no debe establecer una __blockvariable incondicionalmente en cada pasada a través de la enumeración y esperar que sea el "último" valor cuando se usa stoppara terminar antes. Siempre debe acoplar "no, use este objeto" con la configuración stop = YES;.
bbum
@bbum, ¿puede aclarar si el comportamiento continuo se aplica solo a la enumeración concurrente? Si bien es perfectamente comprensible en ese caso, no está documentado, y sería un mordisco bastante sorprendente para la enumeración "en serie".
jscs
4
<rdar: // problem / 15015199> ahora pide una aclaración ya que la documentación no dice de ninguna manera y debería.
bbum