Search code examples
iosobjective-cimageblock

Objective C: For loop is finished before image is finished


I have an arrayOfLinks that contains a lot of url links. I need to get images from these links. I am using the following code to do so.

- (void)getImages {
    NSArray *links = arrayOfLinks;

    for (NSString *link in links ) {
            [self.picImage sd_setImageWithURL:[NSURL URLWithString:link] placeholderImage:nil options:SDWebImageHighPriority completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
                NSLog(@"pic image set finished");
            }];
        }
           [self finishSettingImages];
           NSLog(@"for loop finished");
    }

This almost works, but the problem is the for loop finishes before the images are set. I want to call the method finishSettingImages after each image is set. What would be the best way to do this?

Edit: I want the method 'finishSettingImages' called after ALL the images are set. Sorry for not clarifying this.


Solution

  • Just use GCD groups.

        NSArray *links = arrayOfLinks;
    
        dispatch_group_t group = dispatch_group_create();
    
        for (NSString *link in links) {
    
            dispatch_group_enter(group);
    
            [self.picImage sd_setImageWithURL:[NSURL URLWithString:link] placeholderImage:nil options:SDWebImageHighPriority completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
                dispatch_group_leave(group);
            }];
        }
    
        // you can use dispatch_get_main_queue() or background here
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            // all is done            
        });
    

    If you only need to get images, you can use SDWebImageManager:

        NSArray *links = arrayOfLinks;
    
        __block NSMutableArray *images = [NSMutableArray new];
    
        dispatch_group_t group = dispatch_group_create();
    
        for (NSString *link in links) {
    
            dispatch_group_enter(group);
            SDWebImageManager *manager = [SDWebImageManager sharedManager];
    
            [manager downloadImageWithURL:[NSURL URLWithString:link]
                                  options:SDWebImageRetryFailed
                                 progress:^(NSInteger receivedSize, NSInteger expectedSize) {}
                                completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
                                    if (image) {
                                       [images addObject:image];
                                    } 
                                    dispatch_group_leave(group);
                                }];
    
        }
    
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            // all is done
            for (UIImage *image in images) {
                //do something with images
            }
        });
    

    Code example for Swift 3/4:

    var arrayOfLinks = ... // you string links are here
    
    let dispatchGroup = DispatchGroup()
    
    for link in arrayOfLinks {
        if let url = URL(string: link) {
            dispatchGroup.enter()
            self.imageView.sd_setImage(with: url) { (image, error, cacheType, url) in
                dispatchGroup.leave()
            }
        }
    }
    
    dispatchGroup.notify(queue: .main) {
        print("all is done ")
    }