Repository: SDWebImage/SDWebImage
File: SDWebImage/SDWebImagePrefetcher.m (Objective-C)

Code before:
    [self addRunningToken:token];
    
    NSPointerArray *operations = token.operations;
    for (NSURL *url in urls) {
        __weak typeof(self) wself = self;
        id<SDWebImageOperation> operation = [self.manager loadImageWithURL:url options:self.options context:self.context progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
            __strong typeof(wself) sself = wself;
            if (!sself) {
                return;
            }
            if (!finished) {
                return;
            }
            atomic_fetch_add_explicit(&(token->_finishedCount), 1, memory_order_relaxed);
            if (error) {
                // Add last failed
                atomic_fetch_add_explicit(&(token->_skippedCount), 1, memory_order_relaxed);
            }
            
            // Current operation finished
            [sself callProgressBlockForToken:token imageURL:imageURL];
            
            if (atomic_load_explicit(&(token->_finishedCount), memory_order_relaxed) + atomic_load_explicit(&(token->_skippedCount), memory_order_relaxed) >= atomic_load_explicit(&(token->_totalCount), memory_order_relaxed)) {
                // All finished
                [sself callCompletionBlockForToken:token];
                [sself removeRunningToken:token];
            }
        }];
        @synchronized (token) {
            [operations addPointer:(__bridge void *)operation];
        }
    }
    
    return token;
}

#pragma mark - Cancel
- (void)cancelPrefetching {
    @synchronized(self.runningTokens) {
        NSSet<SDWebImagePrefetchToken *> *copiedTokens = [self.runningTokens copy];
        [copiedTokens makeObjectsPerformSelector:@selector(cancel)];
        [self.runningTokens removeAllObjects];
    }
}

- (void)callProgressBlockForToken:(SDWebImagePrefetchToken *)token imageURL:(NSURL *)url {
    if (!token) {
        return;
    }
    BOOL shouldCallDelegate = [self.delegate respondsToSelector:@selector(imagePrefetcher:didPrefetchURL:finishedCount:totalCount:)];
    NSUInteger tokenFinishedCount = [self tokenFinishedCount];

Review comment (suggestion):
Let's only make the `_finishedCount` to compare with `_totalCount`. `_skippedCount` is not necessary IMO.

Code after:
    token.operations = [NSPointerArray weakObjectsPointerArray];
    token.progressBlock = progressBlock;
    token.completionBlock = completionBlock;
    [self addRunningToken:token];
    
    NSPointerArray *operations = token.operations;
    for (NSURL *url in urls) {
        __weak typeof(self) wself = self;
        id<SDWebImageOperation> operation = [self.manager loadImageWithURL:url options:self.options context:self.context progress:nil completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, SDImageCacheType cacheType, BOOL finished, NSURL * _Nullable imageURL) {
            __strong typeof(wself) sself = wself;
            if (!sself) {
                return;
            }
            if (!finished) {
                return;
            }
            atomic_fetch_add_explicit(&(token->_finishedCount), 1, memory_order_relaxed);
            if (error) {
                // Add last failed
                atomic_fetch_add_explicit(&(token->_skippedCount), 1, memory_order_relaxed);
            }
            
            // Current operation finished
            [sself callProgressBlockForToken:token imageURL:imageURL];
            
            if (atomic_load_explicit(&(token->_finishedCount), memory_order_relaxed) == token->_totalCount) {
                // All finished
                if (!atomic_flag_test_and_set_explicit(&(token->_isAllFinished), memory_order_relaxed)) {
                    [sself callCompletionBlockForToken:token];
                    [sself removeRunningToken:token];
                }
            }
        }];
        @synchronized (token) {
            [operations addPointer:(__bridge void *)operation];
        }
    }
    
    return token;
}

#pragma mark - Cancel
- (void)cancelPrefetching {
    @synchronized(self.runningTokens) {
        NSSet<SDWebImagePrefetchToken *> *copiedTokens = [self.runningTokens copy];
        [copiedTokens makeObjectsPerformSelector:@selector(cancel)];
        [self.runningTokens removeAllObjects];
    }
}

- (void)callProgressBlockForToken:(SDWebImagePrefetchToken *)token imageURL:(NSURL *)url {