Jaki jest argument stop BOOL * dla enumerateObjectsUsingBlock: używany do?

87

enumerateObjectsUsingBlock:Ostatnio często używam do moich potrzeb związanych z szybkim wyliczaniem i mam trudności ze zrozumieniem użycia BOOL *stopw bloku wyliczania.

Stany NSArrayodniesienia do klasy

stop: Odniesienie do wartości logicznej. Blok może ustawić wartość na, YESaby zatrzymać dalsze przetwarzanie tablicy. stopArgumentem jest argument na zewnątrz tylko. Powinieneś zawsze ustawiać tę wartość logiczną tylko YESw obrębie bloku.

Więc oczywiście mogę dodać następujący tekst w moim bloku, aby zatrzymać wyliczanie:

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

Z tego co udało mi się powiedzieć, nie jest wyraźnie ustalone *stop, aby YESnie mieć żadnych skutków ubocznych negatywnych. Wyliczenie wydaje się automatycznie zatrzymywać się na końcu tablicy. Czy więc używanie jest *stopnaprawdę konieczne w bloku?

Mick MacCallum
źródło

Odpowiedzi:

156

stopArgument bloku pozwala zatrzymać wyliczanie przedwcześnie . To odpowiednik breaknormalnej forpętli. Możesz to zignorować, jeśli chcesz przejść przez każdy obiekt w tablicy.

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

Jest to parametr wyjściowy, ponieważ jest to odniesienie do zmiennej z zakresu wywołującego. Musi być ustawiony w Twoim bloku, ale czytaj go w środku enumerateObjectsUsingBlock:, w ten sam sposób, w jaki NSErrors są zwykle przekazywane z powrotem do twojego kodu z wywołań frameworka.

- (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
źródło
21
Zwróć uwagę, że stopflaga jest zalecana; wyliczanie może być kontynuowane na przykład dla pewnej nieokreślonej liczby iteracji w przypadku równoległym. To znaczy, nie powinieneś __blockbezwarunkowo ustawiać zmiennej przy każdym przejściu przez wyliczenie i oczekiwać, że będzie to ostatnia wartość, gdy używasz jej stopdo wcześniejszego zakończenia. Zawsze powinieneś łączyć „nie, użyj tego obiektu” z ustawieniem stop = YES;.
bbum
@bbum, czy możesz wyjaśnić, czy zachowanie ciągłe dotyczy tylko równoczesnego wyliczania? Chociaż jest to całkowicie zrozumiałe w tym przypadku, nie jest to udokumentowane i byłoby dość zaskakującym ugryzieniem w tyłek za „seryjne” wyliczanie.
jscs
4
<rdar: // problem / 15015199> prosi teraz o wyjaśnienie, ponieważ dokumentacja nie określa żadnego sposobu, a powinno.
bbum