How to re-add operations when they fail using enqu

2020-06-07 05:00发布

I have a method that downloads a list of files from a web server to an iPad using the AFNetworking call enqueueBatchOfHTTPRequestOperations. Every once in a while I get a failed operation (usually when the file is larger). Historically, I downloaded each file individually and simply called the operation again up to a certain retry count.

I've refactored the code to use enqueueBatchOfHTTPRequestOperations. This works great but I don't know how to get notifications on "specific" operation failures and I don't know how to re-add them to the queue if they have failed.

Here's the code I'm using to download "n" numbers of files:

    NSMutableArray *operationsArray = [[NSMutableArray alloc]init];
for (MINPageDefinition *currPage in [[MINPageStore sharedInstance] pageArray])
{
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSString *serverLibraryURL = [defaults objectForKey:kRootURL];
    serverLibraryURL = [serverLibraryURL stringByAppendingPathComponent:kPageDefinitionsDirectory];
    serverLibraryURL = [serverLibraryURL stringByAppendingPathComponent:currPage.pageImageName];

    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:serverLibraryURL]];
    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
    operation.outputStream = [NSOutputStream outputStreamToFileAtPath:currPage.pageImageURL append:NO];

    [operationsArray addObject:operation];
}
if ([operationsArray count] > 0)
{
    AFHTTPClient *client = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:@""]];
    void (^progressBlock)(NSUInteger numberOfCompletedOperations, NSUInteger totalNumberOfOperations) = ^(NSUInteger numberOfCompletedOperations, NSUInteger totalNumberOfOperations) {
        NSLog(@"%d proccesses completed out of %d", numberOfCompletedOperations, totalNumberOfOperations);
    };
    void (^completionBlock)(NSArray *operations) = ^(NSArray *operations) {
        NSLog(@"All operations completed");
    };
    [client enqueueBatchOfHTTPRequestOperations:operationsArray
                                  progressBlock:progressBlock
                                completionBlock:completionBlock];
}

Before, I had a method that executed the operation. On failure, the failure block would call itself recursively. How can I modify this code to retry up to "n" numbers of times if an operation fails?

3条回答
别忘想泡老子
2楼-- · 2020-06-07 05:35

I think AFNetworking Auto-Retry might be helpful.

Or you can override following method in your AFHTTPClient.

Consider resumeTasksArray = array of operations which you need to re add to the queue.

NSMutableArray *resumeTasksArray; before @implementation AFHTTPClient 

- (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)request
                                                success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
                                                failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure {

void(^authFailBlock)(AFHTTPRequestOperation *opr, NSError *err) = ^(AFHTTPRequestOperation *opr, NSError *err){
    [resumeTasksArray addObject:request];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
        //now, queue up and execute the original task
        for (NSURLRequest *previousRequest in resumeTasksArray) {
            NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^Resume Task URL - %@", previousRequest.URL);
            NSMutableURLRequest *newRequest = [previousRequest mutableCopy];
            [newRequest setValue:[NSString stringWithFormat:@"Bearer %@", AppSingleton.access_token] forHTTPHeaderField:@"Authorization"];
            AFHTTPRequestOperation *opera10n = [[AFHTTPRequestOperation alloc]initWithRequest:newRequest];
            opera10n.responseSerializer = self.responseSerializer;
            [opera10n setCompletionBlockWithSuccess:success failure:failure];
            if (![[self.operationQueue operations] containsObject:opera10n]) {
                [[self operationQueue] addOperation:opera10n];
                [opera10n start];
            }
        }
        [resumeTasksArray removeAllObjects];
    });
};
AFHTTPRequestOperation *operation = [super HTTPRequestOperationWithRequest:request success:success failure:authFailBlock];
return operation;
}
查看更多
▲ chillily
3楼-- · 2020-06-07 05:39

Check Below Code @justLearningAgain

[[WfServices sharedClient] GET:kGetAddress parameters:dicParam  success:^(AFHTTPRequestOperation *operation, id responseObject) {
        NSLog(@"RESPONSE ::: %@",responseObject);
  }failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    }];


+ (WfServices *)sharedClient
{
    static WfServices * _sharedClient = nil;
    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{
        _sharedClient = [[WfServices alloc] initWithBaseURL:[NSURL URLWithString:kWFBaseURLString]];
    });

    return _sharedClient;
}
查看更多
对你真心纯属浪费
4楼-- · 2020-06-07 05:44

Can't you just enqueue the single failed operation again in that operation's failure block like so?

[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
     [[APIClient sharedClient] enqueueHTTPRequestOperation:operation];
}];

Where [APIClient sharedClient] is a reference to your AFHTTPClient subclass (singleton or not).

查看更多
登录 后发表回答