一个一个地发送一堆请求

时间:2013-12-09 15:34:13

标签: ios objective-c multithreading afnetworking afnetworking-2

我需要逐个向我的服务器发送100个网络请求,并在第100个完成时收到通知。

我正在使用AFNetworking,正在考虑解决这个问题。谁能推荐我一些东西?

2 个答案:

答案 0 :(得分:3)

有几点想法:

  1. 如果真的要按顺序运行每个请求(即一个接一个),你可以这样做:

    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];
    
  2. 对我来说,问题是你是否绝对只想一次运行一个。你为此付出了重大的性能损失。通常,您将使用第一个代码示例(其中唯一的显式依赖项是完成操作)并将maxConcurrentOperationCount设置为类似4的内容,享受并发性及其后续的显着性能提升(同时时间,将并发程度限制在一些合理的数字,不会耗尽所有工作线程,冒着请求超时的风险等等。)

  3. 你还没有说过这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];
    }];
}