Wofür wird das BOOL * stop-Argument für enumerateObjectsUsingBlock verwendet?

87

Ich habe in enumerateObjectsUsingBlock:letzter Zeit viel für meine Anforderungen an die schnelle Aufzählung verwendet, und es fällt mir schwer, die Verwendung BOOL *stopim Aufzählungsblock zu verstehen .

Die NSArrayKlassenreferenzzustände

stop: Ein Verweis auf einen Booleschen Wert. Der Block kann den Wert auf setzen YES, um die weitere Verarbeitung des Arrays zu stoppen. Das stopArgument ist ein reines Argument. Sie sollten diesen Booleschen Wert immer nur YESinnerhalb des Blocks festlegen .

Dann kann ich natürlich Folgendes in meinen Block einfügen, um die Aufzählung zu stoppen:

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

Von dem, was ich habe Einstellung sagen kann, nicht explizit *stopauf YESkeine negativen Nebenwirkungen hat. Die Aufzählung scheint sich am Ende des Arrays automatisch zu stoppen. Ist die Verwendung *stopin einem Block also wirklich notwendig?

Mick MacCallum
quelle

Antworten:

156

Mit dem stopArgument für den Block können Sie die Aufzählung vorzeitig beenden . Es ist das Äquivalent breakeiner normalen forSchleife. Sie können es ignorieren, wenn Sie jedes Objekt im Array durchgehen möchten.

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

Dies ist ein out-Parameter, da er auf eine Variable aus dem aufrufenden Bereich verweist. Es muss in Ihrem Block festgelegt, aber innerhalb von gelesen werden enumerateObjectsUsingBlock:, genauso wie NSErrors normalerweise von Framework-Aufrufen an Ihren Code zurückgegeben werden.

- (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
quelle
21
Beachten Sie, dass die stopFlagge eine Empfehlung ist. Die Aufzählung kann beispielsweise für eine undefinierte Anzahl von Iterationen im gleichzeitigen Fall fortgesetzt werden. Das heißt, Sie sollten eine __blockVariable nicht unbedingt bei jedem Durchlauf durch die Aufzählung festlegen und erwarten, dass sie der "letzte" Wert ist, wenn Sie sie stopzum vorzeitigen Beenden verwenden. Sie sollten immer das "Nein, benutze dieses Objekt" mit der Einstellung koppelnstop = YES; .
bbum
@bbum, können Sie klären, ob das fortgesetzte Verhalten nur für die gleichzeitige Aufzählung gilt? Obwohl es in diesem Fall vollkommen verständlich ist, ist es nicht dokumentiert und wäre für die "serielle" Aufzählung ein ziemlich überraschender Biss in den Arsch.
Jscs
4
<rdar: // problem / 15015199> bittet jetzt um Klarstellung, da die Dokumentation dies nicht so oder so sagt und sollte.
bbum