目标C:在图像完成之前完成循环

时间:2016-11-21 17:44:43

标签: ios objective-c image block

我有一个包含很多网址链接的arrayOfLinks。我需要从这些链接获取图像。我使用以下代码来执行此操作。

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

这几乎可以工作,但问题是在设置图像之前for循环完成。我想在设置每个图像后调用方法finishSettingImages。最好的方法是什么?

编辑:我希望在设置所有图像后调用方法'finishSettingImages'。很抱歉没有澄清这一点。

2 个答案:

答案 0 :(得分:3)

只需使用GCD组。

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

如果您只需要获取图像,可以使用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
        }
    });

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 ")
}

答案 1 :(得分:0)

编辑:这个答案很糟糕,正如Josh在评论中指出的那样,我没有看到index == total支票的竞争条件

试试这个:

- (void)getImages 
{
   NSArray *links = arrayOfLinks;
   NSUInteger total = [links count];
   __block NSUInteger index = 0;
   __weak id *weakSelf = self; //if your picImage retains the completion block as a property, 
   //then you will want to capture a weak reference to self, so you don't have a retain cycle
   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");
         index += 1;
         if( index == total )
         {
            //again if you don't store this block as a property, you can just reference self instead of weakSelf
            [weakSelf finishSettingImages];
         }
      }];
   }
   NSLog(@"for loop finished");
}

__block属性使块使用指向变量的指针,以便它可以修改块执行的值。这就是我们如何增加索引变量的方法。 total不是__block所以当您定义块时total的当前状态是每次块执行时将使用的内容。因此,即使您在块中total设置10010,下次块执行时仍会看到total10