Search code examples
cobjective-cpointersprimitive

In Objective-C (or C), how does this code with pointer to a bool work?


How does the stop mechanism work in this code?

@interface GifAnaimator()
@property BOOL stopping;
@end

@implementation GifAnaimator
- (void)startWithURL:(CFURLRef)imageURL {
    __weak GifAnaimator *weakSelf = self;
    CGAnimateImageAtURLWithBlock(imageURL, nil, ^(size_t index, CGImageRef image, bool* stop) {
        // Some image handling code...
        *stop = weakSelf.stopping;
    });
}

- (void)stop {
    self.stopping = YES;
}
@end

What's confusing me about this code is that the dereferenced stop is assigned a plain, non-pointed to, BOOL, stopping. Afterwards, when stopping is mutated, stop somehow gets the same mutation.

I tried capturing stop in a block, and calling the block later on to mutate it like so:

weakSelf.stopAnimation = ^{
   *stop = YES;
};

This code makes more sense to me but it doesn't work.

What exactly is happening here?


Solution

  • The documentation comment for CGAnimateImageAtURLWithBlock says:

    /* Animate the sequence of images contained in the file at `url'. Currently supported image
     * formats are GIF and APNG. The `options' dictionary may be used to request additional playback
     * options; see the list of keys above for more information. The block is called on the main queue
     * at time intervals specified by the `delay time' of the image. The animation can be stopped by
     * setting the boolean parameter of the block to false.
     */
    

    If self.stopping is mutated and *stop later gets the same mutation I assume that's because the block is called after the value of self.stopping is changed and the block sets *stop to that value.

    Capturing *stop won't work because in all likelihood it doesn't exist outside of the block.

    NSDictionary has a method with a similar signature:

    - (void)enumerateKeysAndObjectsWithOptions:(NSEnumerationOptions)opts 
                                    usingBlock:(void (^)(KeyType key, ObjectType obj, BOOL *stop))block
    

    In pseudo code this does something like:

    for (key, object) in storage {
        BOOL stop = NO;
        block(key, object, &stop);
        if(stop) {
            break;
        }
    }
    

    So stop does not exist outside of the closure.