我需要逐个向我的服务器发送100个网络请求,并在第100个完成时收到通知。
我正在使用AFNetworking,正在考虑解决这个问题。谁能推荐我一些东西?
答案 0 :(得分:3)
有几点想法:
如果真的要按顺序运行每个请求(即一个接一个),你可以这样做:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 1;
NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"All operations done");
}];
for (NSInteger i = 0; i < operationCount; i++) {
AFHTTPRequestOperation *operation = ... // create your operation here
[completionOperation addDependency:operation];
[queue addOperation:operation];
}
[queue addOperation:completionOperation];
注意,使用这样的操作队列提供的优势是,如果需要,您可以轻松取消该队列中的所有操作。
如果执行这些操作的顺序很关键,您可能希望在操作之间建立明确的依赖关系,例如:
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 1;
NSOperation *completionOperation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"All operations done");
}];
NSOperation *priorOperation = nil;
for (NSInteger i = 0; i < operationCount; i++) {
AFHTTPRequestOperation *operation = ... // create your operation here
[completionOperation addDependency:operation];
if (priorOperation) [operation addDependency:priorOperation];
[queue addOperation:operation];
priorOperation = operation;
}
[queue addOperation:completionOperation];
对我来说,问题是你是否绝对只想一次运行一个。你为此付出了重大的性能损失。通常,您将使用第一个代码示例(其中唯一的显式依赖项是完成操作)并将maxConcurrentOperationCount
设置为类似4
的内容,享受并发性及其后续的显着性能提升(同时时间,将并发程度限制在一些合理的数字,不会耗尽所有工作线程,冒着请求超时的风险等等。)
你还没有说过这100个操作是什么,但如果它是一堆下载,你可能想要考虑一个“延迟加载”模式,根据需要异步加载数据,而不是全部一次。
例如,如果下载图像,您可以使用AFNetworking UIImageView
类别实现此目的。
答案 1 :(得分:0)
这是一个常见问题的特定形式,即“我如何调用一系列块操作并在最后一个完成时得到通知?”
一个想法是使用每个请求的参数制作“待办事项列表”。假设每个请求的数字为0..99。现在伪代码看起来像这样:
@property(nonatomic, copy) void (^done)(BOOL); // we'll need to save a completion block
@property(nonatomic, strong) NSMutableArray *todo; // might as well save this too
- (void)makeRequestsThenInvoke:(void (^)(BOOL))done {
self.todo = [NSMutableArray arrayWithArray:@[@99, @98, @97 ... @0]];
// make this in a loop using real params to your network request (whatever distinguishes each request)
self.done = done;
[self makeRequests];
}
- (void)makeRequests {
if (!self.todo.count) { // nothing todo? then we're done
self.done(YES);
self.done = nil; // avoid caller-side retain cycle
return;
}
// otherwise, get the next item todo
NSNumber *param = [self.todo lastObject];
// build a url with param, e.g. http://myservice.com/request?param=%@ <- param goes there
[afManager post:url success:success:^(AFHTTPRequestOperation *operation, id responseObject) {
// handle the result
// now update the todo list
[self.todo removeLastObject];
// call ourself to do more, but use performSelector so we don't wind up the stack
[self performSelector:@selector(makeRequests) withObject:nil afterDelay:0.0];
}];
}