【问题标题】:Objective C: For loop is finished before image is finished目标 C:在图像完成之前完成 For 循环
【发布时间】:2016-11-21 17:44:42
【问题描述】:

我有一个arrayOfLinks,其中包含很多 url 链接。我需要从这些链接中获取图像。我正在使用以下代码来执行此操作。

- (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”。很抱歉没有澄清这一点。

【问题讨论】:

  • 每个之后,还是在所有完成后仅在最后一次?
  • 全部完成后。抱歉,我会确保对其进行编辑以澄清它。

标签: ios objective-c image block


【解决方案1】:

只需使用 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 ")
}

【讨论】:

    【解决方案2】:

    编辑:这个答案很糟糕,正如 cmets 中的 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 的当前状态是每次块执行时将使用的状态。因此,即使您在块内将total10 设置为100,下次执行该块时,它仍会将total 视为10

    【讨论】:

    • 这里有一个竞争条件:finishSettingImages 可以运行多次,如果在它们的任何相应比较之前运行多个增量。
    • 啊是的好电话。我挂断了使用__block 的答案没有看到
    猜你喜欢
    • 1970-01-01
    • 2021-11-25
    • 1970-01-01
    • 1970-01-01
    • 2012-06-26
    • 2017-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多