objective-ccocoa-touchnsarrayenumerationfast-enumeration

What is the BOOL *stop argument for enumerateObjectsUsingBlock: used for?


I've been using enumerateObjectsUsingBlock: a lot lately for my fast-enumeration needs, and I'm having a hard time understanding the usage of BOOL *stop in the enumeration block.

The NSArray class reference states

stop: A reference to a Boolean value. The block can set the value to YES to stop further processing of the array. The stop argument is an out-only argument. You should only ever set this Boolean to YES within the Block.

So then of course I can add the following in my block to stop the enumeration:

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

From what I've been able to tell, not explicitly setting *stop to YES doesn't have any negative side effects. The enumeration seems to automatically stop itself at the end of the array. So is using *stop really necessary in a block?


Solution

  • The stop argument to the Block allows you to stop the enumeration prematurely. It's the equivalent of break from a normal for loop. You can ignore it if you want to go through every object in the 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];
    }];
    

    That is an out parameter because it is a reference to a variable from the calling scope. It needs to be set inside your Block, but read inside of enumerateObjectsUsingBlock:, the same way NSErrors are commonly passed back to your code from framework calls.

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