2016-05-19 5 views
1

Я использую AFNetworking для всего моего общения с моим сервером, все помещается в отдельный класс под названием «APIConnector».AFNetworking 3 Async download download queue

Я пытаюсь загрузить пользователя. Когда у меня есть идентификатор пользователя, я могу создать URL-адрес, но я не знаю, какие пользователи я получаю с сервера, прежде чем я их получу. Код, который я сейчас выглядит следующим образом:

AFHTTPSessionManager *httpManager = [AFHTTPSessionManager manager]; 
AFHTTPSessionManager *imageManager = [AFHTTPSessionManager manager]; //Used for posting to the server 
    [httpManager POST:url parameters:dict progress:nil 
       success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 
        UIImageView *imageHolder = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"placeholder"]]; 
        if (isUser) { 
         NSMutableArray *users = [NSMutableArray new]; 
         int i = 1; 
         for (id userResult in responseObject) { 
          User *user = [[User alloc] initWithId:[userResult valueForKey:@"index"] name:[userResult valueForKey:@"name"]]; 
          user.imageURL = [NSString stringWithFormat:@"%@/image/?index=%@&imgIndex=0",backendURL,user.userID]; 
          [users addObject:user]; 
          if (i == [responseObject count]) { 
           success(users); 
          } 
          i++; 
         } 

Я сделал несколько итераций меняется несколько вещей, попробовав его, как это, а также, как это, но с операциями:

AFHTTPSessionManager *imageManager = [AFHTTPSessionManager manager]; //Used for posting to the server 
    [httpManager POST:url parameters:dict progress:nil 
       success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 
        UIImageView *imageHolder = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"placeholder"]]; 
        if (isUser) { 
         NSMutableArray *users = [NSMutableArray new]; 
         int i = 1; 
         for (id userResult in responseObject) { 
          User *user = [[User alloc] initWithId:[userResult valueForKey:@"index"] name:[userResult valueForKey:@"name"]]; 
          user.imageURL = [NSString stringWithFormat:@"url to image"]; 
          [users addObject:user]; 
          if (i == [responseObject count]) { 
           success(users); 
          } 
          i++; 
         } 
         NSMutableArray *usersWithImage = [NSMutableArray new]; 
         for (int i = 0; i < users.count;i++) { 
          User *userImg = [users objectAtIndex:i]; 
          NSString *imageURL = [NSString stringWithFormat:@"%@/image/?index=%@&imgIndex=0",backendURL,userImg.userID]; 
          imageManager.responseSerializer = [AFImageResponseSerializer serializer]; 
          [imageManager GET:imageURL parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable imgResponse) { 
           User *user = userImg;[users objectAtIndex:i]; 
           user.profilePic.image = imgResponse; 
           [usersWithImage addObject:user]; 

           if (i == users.count-1) { 
            success(usersWithImage); 
           } 
          } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { 
           NSLog(@"Error: %@",error); 
          }]; 

It ' «работает»», но он просто загружает последнее изображение как все изображения, я также пытался: https://github.com/robertmryan/AFHTTPSessionOperation/ же результат

EDIT/ADD:

NSMutableArray *users = [NSMutableArray new]; 
dispatch_group_t group = dispatch_group_create(); 
for (id acResult in responseObject) { 
    User *user = [[User alloc]initWithId:[acResult valueForKey:@"index"] name:[acResult valueForKey:@"name"]]; 
    NSString *imageURL = [NSString stringWithFormat:@"%@/image/?index=%@&imgIndex=0",backendURL,user.userID]; 
    dispatch_group_enter(group); 
    [imageManager GET:imageURL parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 
    user.imageData = UIImageJPEGRepresentation(responseObject, 1); 
    [users addObject:user]; 
    dispatch_group_leave(group);  // leave if successful 
    } 
failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { 
    NSLog(@"Error: %@",error); 
    dispatch_group_leave(group);  // leave if not 
    }]; 
} 

dispatch_group_notify (group, dispatch_get_main_queue(),^{ успех (деятельность); // Это никогда не называется }); Также у меня есть контроль над количеством пользователей (только 10 за звонок), но я не знаю, какой у них идентификатор.

+0

Когда вы говорите «просто загружает последнее изображение», подтвердили ли вы, сколько раз «GET» вызывается внутри цикла 'for'? Кроме того, что такое 'profilePic' внутри объекта' User'? Похоже, что это может быть образ, но вы действительно не должны иметь объекты пользовательского интерфейса внутри вашей модели. – Rob

+0

Кстати, где установлен 'userID'. Я не вижу, чтобы вы установили это при загрузке списка пользователей. Итак, как это узнать, что использовать значение 'userID'? – Rob

+0

Последнее замечание: я бы посоветовал проверить инструмент, подобный [Charles] (http://charlesproxy.com), который полезен при диагностировании подобных проблем. Вы можете просматривать запросы и ответы в независимом инструменте, и это позволяет легко идентифицировать источник проблемы. – Rob

ответ

4

В вашем втором примере, у вас есть:

if (i == users.count-1) { 
    success(usersWithImage); 
} 

Вы должны либо использовать диспетчерскую группу или NSOperation обертки, чтобы определить, когда все загрузки сделаны, например:

imageManager.responseSerializer = [AFImageResponseSerializer serializer]; // you only have to do this once 

NSMutableArray *usersWithImage = [NSMutableArray new]; 

dispatch_group_t group = dispatch_group_create(); 

for (User *user in users) { 
    NSString *imageURL = [NSString stringWithFormat:@"%@/image/?index=%@&imgIndex=0", backendURL, user.userID]; 
    dispatch_group_enter(group); 
    [imageManager GET:imageURL parameters:nil progress:nil success:^(NSURLSessionDataTask *task, id imgResponse) { 
     user.profilePic.image = imgResponse; // this line is worrying, though: What are you doing here 
     [usersWithImage addObject:user]; 
     dispatch_group_leave(group);   // leave if successful 
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { 
     NSLog(@"Error: %@",error); 
     dispatch_group_leave(group);   // leave if not 
    }]; 
} 
dispatch_group_notify(group, dispatch_get_main_queue(), ^{ 
    success(usersWithImage); 
}); 

I должен признаться, однако, что я нахожу ссылку на user.profilePic.image немного волнуюсь. Это ссылка UIKit? У вас не должно быть элементов управления UIKit в объекте модели.


В более широком вопросе, если вы не знаете, сколько пользователей вы можете быть извлечения, загрузки всех изображений не может быть разумное использование памяти и сетевых ресурсов. Что, если было 100 пользователей? Загрузка списка из 100 пользователей будет быстрой, но загрузка 100 изображений не будет. Как правило, вы должны просто сохранить URL-адрес изображения в своей модели, но не запрашивать изображения до тех пор, пока им не понадобится пользовательский интерфейс (и загружайте только те из них, которые нужны, например, если только 12 строк видны, загружайте только эти 12 изображений). Если вы ищете «[ios] ленивые загрузки изображений», вы, вероятно, найдете много дискуссий по этой теме.

Лично, учитывая, что вы уже используете AFNetworking, я был бы склонен использовать категорию UIImageView+AFNetworking (находится в папке UIKit+AFNetworking). Это действительно изящный способ сделать ленивый асинхронный поиск изображений для UIImageView в UITableViewCell.

+0

Лучше ли сохранять URL-адрес, потому что я пытаюсь это и просто загружаю, как вы упомянули, когда пользователю это нужно. Но я создаю приложение, в котором пользователь будет быстро просматривать изображения (думаю, как люди прокручивают других людей на Tinder), и мне бы хотелось, чтобы пакет был загружен и готов обслуживать пользователя. Я также ответил на более широкую проблему в ОП. – 4FunAndProfit

+0

Лично я бы сосредоточился на ленивой загрузке изображений, работающих в первую очередь, убедившись, что это кеширование правильное и все такое хорошее. Затем я решал проблему «предварительного нагрева» загрузки изображений для соседних ячеек. Но делать это правильно нетривиально, поэтому я думал, что что-то вроде «UIImageView + AFNetworking» может помочь. – Rob

+0

Да, это хороший момент! Хорошо, поэтому вы полагаете, что я должен использовать группы отправки? Потому что уведомитель никогда не срабатывает? Он достигает запроса GET, который я могу сказать из отладки, но почему-то никогда не заходит внутрь? Ну, мне нужно сделать вызов в dispatch_get_main_queue? Я обновил последний пример, используя NSData и группы отправки – 4FunAndProfit