2016-11-21 3 views
2

У меня есть arrayOfLinks, который содержит много ссылок на URL. Мне нужно получить изображения из этих ссылок. Для этого я использую следующий код.Цель C: для завершения цикла до завершения изображения

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

Это почти работает, но проблема заключается в том, что контуры цикла заканчиваются перед установкой изображений. Я хочу вызвать метод finishSettingImages после установки каждого изображения. Какой был бы лучший способ сделать это?

Редактировать: Я хочу, чтобы метод «finishSettingImages» вызывался после ВСЕГО изображений. Извините, что не уточнил это.

+0

После _each_, или только один раз в конце после _все_ из них сделаны? –

+0

как только все они будут выполнены. Извините, я обязательно отредактирую его, чтобы уточнить его. – Weakman10122

ответ

2

Просто используйте группы 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 
     } 
    }); 
0

EDIT: этот ответ плохо, как Джош в комментариях указал, я не смог увидеть состояние гонки с 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 в 100 от 10 внутри блока, в следующий раз, когда блок выполнит его, он все равно увидит total как 10.

+1

У вас есть условие гонки здесь: 'finishSettingImages' может запускаться более одного раза, если перед каждым их сопоставлением выполняются несколько приращений. –

+0

Ах, да, хороший звонок. Я повесил трубку на ответ, используя '__block', не увидел, что –

Смежные вопросы