Я использую 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. Есть ли лучший способ (кроме сохранения данных в каждой операции и последующего чтения из хранилища в последующей операции) для передачи данных между зависимыми операциями в пакете?
Наконец, мне приходит в голову, что я, возможно, усложняю весь этот процесс, чем он должен быть. Я хотел бы услышать об альтернативных подходах, которые по-прежнему обеспечивают общую параллельную очередь, по-прежнему обеспечивают общее отслеживание хода выполнения/завершения пакета, но также позволяют управлять зависимостями между операциями и передавать данные. Спасибо!