问题
I need to send 100 network requests to my server one-by-one and get notified when the 100th is done.
I'm using AFNetworking and was thinking about a solution of this problem. Can anyone recommend me something?
回答1:
A couple of thoughts:
If really just going to run each request serially (i.e. one after another), you could do:
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];
Note, using operation queue like this offers the advantage that you can easily cancel all the operations in that queue should you ever need to.
If the order that these are performed is critical, you might want to establish explicit dependencies between the operations, e.g.:
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];
The question for me is whether you absolutely only want to run one at a time. You pay a significant performance penalty for that. Generally you'd use that first code sample (where the only explicit dependencies are to the completion operation) and set
maxConcurrentOperationCount
to something like4
, enjoying concurrency and its consequent significant performance gain (while at the same time, constraining the degree of concurrency to some reasonable number that won't use up all of your worker threads, risk having requests time out, etc.).You haven't said what these 100 operations are, but if it's a bunch of downloads, you might want to consider a "lazy loading" pattern, loading the data asynchronously as you need it, rather than all at once.
If downloading images, for example, you might achieve this using the AFNetworking
UIImageView
category.
回答2:
This is a specific form of a common question, which is "how do I call a sequence of block operations and get notified when the last one finishes?"
One idea is to make a "to-do list" using the parameters for each request. Say each request takes a number 0..99. Now pseudo-code would looks like this:
@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];
}];
}
来源:https://stackoverflow.com/questions/20474422/send-a-bunch-of-requests-one-by-one