How to tell if blocks in loop all have completed executing?

前端 未结 4 1924
一个人的身影
一个人的身影 2020-12-02 19:10

I have a loop set up that downloads a series a images which I will later use for to animate using the animationImages property of UIImageView. I wo

相关标签:
4条回答
  • 2020-12-02 19:55

    Create a dispatch group, in the for loop enter the group, in the completion block leave the group. Then you can use dispatch_group_notify to find out when all blocks have completed:

    dispatch_group_t    group = dispatch_group_create();
    
    for (PFObject *pictureObject in objects){
    
        PFFile *imageFile = [pictureObject objectForKey:@"image"];
        NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url];
        NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL];
    
        dispatch_group_enter(group);
        [tokenImageView setImageWithURLRequest:imageRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
            [self.downloadedUIImages addObject:image]; //This is a mutableArray that will later be set to an UIImageView's animnationImages
            dispatch_group_leave(group);
        } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
            NSLog(@"Error %@", error);
            dispatch_group_leave(group);
        }];
    
    }
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // do your completion stuff here
    });
    
    0 讨论(0)
  • 2020-12-02 19:58
    for (PFObject *pictureObject in objects){
    
        PFFile *imageFile = [pictureObject objectForKey:@"image"];
        NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url];
        NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL];
    
        [tokenImageView setImageWithURLRequest:imageRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
           [self.downloadedUIImages addObject:image]; //This is a mutableArray that will later be set to an UIImageView's animnationImages
           if([[objects lastObject] isEqual:pictureObject]) {
               [self animateImages];
           }
        } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
            NSLog(@"Error %@", error);
            if([[objects lastObject] isEqual:pictureObject]) {
               [self animateImages];
           }
        }];
    
    }
    
    - (void)animateImages {
        //do animation here.
    }
    
    0 讨论(0)
  • 2020-12-02 20:00

    Count how many you've completed. The challenging part is making it thread safe. I recommend creating an atomic counter class for that.

    Generic solution!

    + (void)runBlocksInParallel:(NSArray *)blocks completion:(CompletionBlock)completion {
        AtomicCounter *completionCounter = [[AtomicCounter alloc] initWithValue:blocks.count];
        for (AsyncBlock block in blocks) {
            block(^{
                if ([completionCounter decrementAndGet] == 0) {
                    if (completion) completion();
                }
            });
        }
        if (blocks.count == 0) {
            if (completion) completion();
        }
    }
    

    NSMutableArray *asyncBlocks = [NSMutableArray array];
    for (PFObject *pictureObject in objects){
        [asyncBlocks addObject:^(CompletionBlock completion) {
            PFFile *imageFile = [pictureObject objectForKey:@"image"];
            NSURL *imageFileURL = [[NSURL alloc] initWithString:imageFile.url];
            NSURLRequest *imageRequest = [NSURLRequest requestWithURL:imageFileURL];
    
            [tokenImageView setImageWithURLRequest:imageRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
               [self.downloadedUIImages addObject:image]; //This is a mutableArray that will later be set to an UIImageView's animnationImages
            } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
                NSLog(@"Error %@", error);
            } completion:completion];
        }];
    }
    [BlockRunner runBlocksInParallel:[asyncBlocks copy] completion:^{
        //Do your final completion here!
    }];
    
    0 讨论(0)
  • 2020-12-02 20:14

    Set up a property and initialize it to the number of cycles - objects.count. In the completion of the block, lower the number down. When you reach zero, you are done.

    0 讨论(0)
提交回复
热议问题