Хобрук: Ваш путь к мастерству в программировании

AFNetworking 2, составляющий пакет с зависимостями

Я использую AFNetworking 2 и хотел бы использовать подход NSURLSession, но прочитал проблему GitHub, где Мэтт объясняет, почему это не работает с пакетной обработкой. Поэтому вместо этого я использую AFHTTPRequestOperations из одноэлементного класса, содержащего NSOperationQueue.

Я создал значительное количество дискретных операций. Каждая из этих операций вызывается из разных областей приложения, но в некоторых частях приложения полезно объединять их вместе (подумайте о «полном обновлении»). Вот метод, который делает это:

-(void) getEverything {

  AFHTTPRequestOperation *ssoA = [SecurityOps authenticateSSO];

  AFHTTPRequestOperation *atSC = [SecurityOps attachSessionCookies];
  [atSC addDependency:ssoA];

  AFHTTPRequestOperation *comL = [CommunityOps communityListOp];
  [comL addDependency:ssoA];

  AFHTTPRequestOperation *comS = [CommunityOps searchCommunityOp:nil :nil];
  [comS addDependency:comL];

  AFHTTPRequestOperation *stu1 = [StudentOps fdpFullOp]; // 3 Ops in Sequence
  [stu1 addDependency:ssoA];

  AFHTTPRequestOperation *stu2 = [StudentOps progressDataOp];
  [stu2 addDependency:ssoA];

  AFHTTPRequestOperation *stu3 = [StudentOps programTitleOp];
  [stu3 addDependency:ssoA];

  AFHTTPRequestOperation *stu4 = [StudentOps graduationDateOp];
  [stu4 addDependency:ssoA];

  NSArray *ops = [AFURLConnectionOperation
                  batchOfRequestOperations:@[ssoA, atSC, comL, comS, stu1, stu2, stu3, stu4]
                             progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {

    NSLog(@"%lu of %lu complete", numberOfFinishedOperations, totalNumberOfOperations);

  } completionBlock:^(NSArray *operations) {

    NSLog(@"All operations in batch complete");

  }];

  [self.Que addOperations:ops waitUntilFinished:NO];
}

Это прекрасно работает, за одним исключением: «fdpFullOp» фактически запускает другие операции в последовательности. В своем блоке завершения он добавляет opB в очередь, а затем opB добавляет в очередь opC в своем блоке завершения. Эти дополнительные операции, конечно, не учитываются в «пакете» (как написано выше), поэтому этот пакет завершается до того, как будут выполнены opB и opC.

Вопрос 1. При добавлении операции из блока завершения другого, могу ли я добавить ее в "пакет" (для общего отслеживания выполнения пакета)?

Одна альтернатива, которую я пробовал, состоит в том, чтобы упорядочить все операции в очереди при создании пакета (ниже). Это обеспечивает точное уведомление о завершении партии. Однако, поскольку stu1B требует данных от stu1A, а stu1C требует данных от stu1B, это работает только в том случае, если предшествующие операции сохраняют свои данные где-то (например, NSUserDefaults), чтобы последующие операции могли их получить. Это кажется немного «неэлегантным», но это работает.

-(void) getEverything {

  AFHTTPRequestOperation *ssoA = [SecurityOps authenticateSSO];

  AFHTTPRequestOperation *atSC = [SecurityOps attachSessionCookies];
  [atSC addDependency:ssoA];

  AFHTTPRequestOperation *comL = [CommunityOps communityListOp];
  [comL addDependency:ssoA];

  AFHTTPRequestOperation *comS = [CommunityOps searchCommunityOp:nil :nil];
  [comS addDependency:comL];

  AFHTTPRequestOperation *stu1A = [StudentOps fdpFullOp]; // 1 of 3 op sequence
  [stu1A addDependency:ssoA];

  AFHTTPRequestOperation *stu1B = [StudentOps fdpSessionOp]; // 2 of 3 op sequence
  [stu1B addDependency:stu1A];

  AFHTTPRequestOperation *stu1C = [StudentOps fdpDegreePlanOp]; // 3 of 3 op sequence
  [stu1C addDependency:stu1B];

  AFHTTPRequestOperation *stu2 = [StudentOps progressDataOp];
  [stu2 addDependency:ssoA];

  AFHTTPRequestOperation *stu3 = [StudentOps programTitleOp];
  [stu3 addDependency:ssoA];

  AFHTTPRequestOperation *stu4 = [StudentOps graduationDateOp];
  [stu4 addDependency:ssoA];

  NSArray *ops = [AFURLConnectionOperation
                  batchOfRequestOperations:@[ssoA, atSC, comL, comS, stu1A, stu1B, stu1C, stu2, stu3, stu4]
                             progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {

    NSLog(@"%lu of %lu complete", numberOfFinishedOperations, totalNumberOfOperations);

  } completionBlock:^(NSArray *operations) {

    NSLog(@"All operations in batch complete");

  }];

  [self.Que addOperations:ops waitUntilFinished:NO];
}

Вопрос 2. Есть ли лучший способ (кроме сохранения данных в каждой операции и последующего чтения из хранилища в последующей операции) для передачи данных между зависимыми операциями в пакете?

Наконец, мне приходит в голову, что я, возможно, усложняю весь этот процесс, чем он должен быть. Я хотел бы услышать об альтернативных подходах, которые по-прежнему обеспечивают общую параллельную очередь, по-прежнему обеспечивают общее отслеживание хода выполнения/завершения пакета, но также позволяют управлять зависимостями между операциями и передавать данные. Спасибо!


Ответы:


1

Вы не должны использовать NSOperation зависимости для этого, потому что более поздние операции полагаются на обработку с completionBlock, но NSOperationQueue считает эту работу побочным эффектом.

Согласно документам, completionBlock — это «блок, выполняемый после завершения основной задачи операции». В случае с AFHTTPRequestOperation «основной задачей операции» является «выполнение HTTP-запроса». «Основная задача» не включает синтаксический анализ JSON, сохранение данных, проверку кодов состояния HTTP и т. д. — все это обрабатывается в completionBlock.

Таким образом, в вашем коде, если операция ssoA успешно выполняет сетевой запрос, но аутентификация не удалась, все последующие операции продолжатся.

Вместо этого вы должны просто добавить зависимые операции из блоков завершения более ранних операций.

При добавлении операции из блока завершения другого, могу ли я добавить ее в «пакет» (для общего отслеживания завершения пакета)?

Вы не можете, потому что:

  1. На данный момент слишком поздно создавать пакетную операцию (см. реализация )
  2. Это не имеет смысла, потому что более поздние операции могут никогда не быть созданы (например, если аутентификация не удалась)

В качестве альтернативы вы можете создать один объект NSProgress и обновляйте его по мере продвижения работы, чтобы отразить то, что было сделано, и то, что, как известно, осталось. Вы можете использовать это, например, для обновления файла UIProgressView.

Есть ли лучший способ (кроме сохранения данных в каждой операции и последующего чтения из хранилища в последующей операции) для передачи данных между зависимыми операциями в пакете?

Если вы добавляете зависимые операции из блоков завершения более ранних операций, вы можете просто передавать локальные переменные после проверки условий успеха.

13.07.2015
Новые материалы

Прогресс в технологии Трансформеров часть 3
Многомасштабный управляющий сигнальный преобразователь для бесфазного синтеза движения (arXiv) Автор: Линтао Ван , Кун Ху , Лей Бай , Юй Дин , Ваньли Оуян , Чжиюн Ван . Аннотация:..

Представляем поддержку компонентов Vue.js. Мгновенный HMR и многое другое.
Хотя у FuseBox уже был плагин Vue, он был базовым и не имел многих функций, которые делали работу с Vue.js такой приятной. Однако с этим выпуском мы рады сообщить, что в FuseBox..

Приключения в Javascript, часть 1
Я продолжаю думать о том, чтобы писать больше, но чем больше я думаю об этом, тем меньше я это делаю. Итак, сегодня я перестал думать и начал писать. Отсюда можно только спускаться… В..

Понимание дженериков в TypeScript: подробное руководство
Введение TypeScript, строго типизированный надмножество JavaScript, хорошо известен своей способностью улучшать масштабируемость, удобочитаемость и ремонтопригодность приложений. Одной из..

Учебные заметки JavaScript Object Oriented Labs
Вот моя седьмая неделя обучения программированию. После ruby ​​и его фреймворка rails я начал изучать самый популярный язык интерфейса — javascript. В отличие от ruby, javascript — это более..

Разбор строк запроса в vue.js
Иногда вам нужно получить данные из строк запроса, в этой статье показано, как это сделать. В жизни каждого дизайнера/разработчика наступает момент, когда им необходимо беспрепятственно..

Предсказание моей следующей любимой книги 📚 Благодаря данным Goodreads и машинному обучению 👨‍💻
«Если вы не любите читать, значит, вы не нашли нужную книгу». - J.K. Роулинг Эта статья сильно отличается от тех, к которым вы, возможно, привыкли . Мне очень понравилось поработать над..