À quoi sert l'argument BOOL * stop pour enumerateObjectsUsingBlock: utilisé?

87

J'en ai beaucoup utilisé enumerateObjectsUsingBlock:ces derniers temps pour mes besoins d'énumération rapide, et j'ai du mal à comprendre l'utilisation de BOOL *stopdans le bloc d'énumération.

Les NSArrayétats de référence de classe

stop: Une référence à une valeur booléenne. Le bloc peut définir la valeur sur YESpour arrêter le traitement ultérieur du tableau. L' stopargument est un argument externe. Vous ne devriez jamais définir ce booléen que YESdans le bloc.

Alors bien sûr, je peux ajouter ce qui suit dans mon bloc pour arrêter l'énumération:

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

D'après ce que j'ai pu dire, ne pas définir explicitement *stopsur YESn'a aucun effet secondaire négatif. L'énumération semble s'arrêter automatiquement à la fin du tableau. L'utilisation est-elle *stopvraiment nécessaire dans un bloc?

Mick MacCallum
la source

Réponses:

156

L' stopargument du bloc vous permet d'arrêter l'énumération prématurément . C'est l'équivalent d' breakune forboucle normale . Vous pouvez l'ignorer si vous souhaitez parcourir tous les objets du tableau.

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

C'est un paramètre out car il s'agit d'une référence à une variable de la portée appelante. Il doit être défini dans votre bloc, mais lu à l'intérieur de enumerateObjectsUsingBlock:, de la même manière que les NSErrors sont généralement renvoyés à votre code à partir des appels de 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
la source
21
Notez que le stopdrapeau est consultatif; l'énumération peut continuer pendant un nombre indéfini d'itérations dans le cas simultané, par exemple. C'est-à-dire que vous ne devriez pas définir une __blockvariable inconditionnellement à chaque passage dans l'énumération et vous attendre à ce que ce soit la "dernière" valeur lors de l'utilisation stoppour terminer tôt. Vous devez toujours coupler le "non, utilisez cet objet" avec le paramètre stop = YES;.
bbum
@bbum, pouvez-vous préciser si le comportement continu s'applique uniquement à l'énumération simultanée? Bien que cela soit parfaitement compréhensible dans ce cas, ce n'est pas documenté, et ce serait assez surprenant pour une énumération "en série".
jscs
4
<rdar: // problem / 15015199> demande maintenant des éclaircissements car la documentation ne dit ni l'un ni l'autre et il le devrait.
bbum du