2012-08-31 77 views
20

我最近从ASIHTTPRequest迁移到AFNetworking,这一直是很大的。但是,我连接的服务器有一些问题,有时会导致我的请求超时。当使用ASIHTTPRequest它使用下面的选择AFNetworking - 如何设置请求在发生超时时重试?

-setNumberOfTimesToRetryOnTimeout: 

这可以在这个帖子可以进一步参考,Can an ASIHTTPRequest be retried?

这AFNetworking如果您有可能设置在超时的情况下,请求重试次数不熟悉 https://github.com/AFNetworking/AFNetworking#readme

我无法找到AFNetworking等效的API,有没有人发现,超时使用AFNetworking事件重试网络请求的解决方案? AFNetworking的

回答

56

马特·汤普森开发商还跟回答这个对我来说。以下是解释解决方案的github链接。

https://github.com/AFNetworking/AFNetworking/issues/393

基本上AFNetworking不支持此功能。它留给了开发者对个案基础上实现如下图所示

- (void)downloadFileRetryingNumberOfTimes:(NSUInteger)ntimes 
           success:(void (^)(id responseObject))success 
           failure:(void (^)(NSError *error))failure 
{ 
    if (ntimes <= 0) { 
     if (failure) { 
      NSError *error = ...; 
      failure(error); 
     } 
    } else { 
     [self getPath:@"/path/to/file" parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) { 
      if (success) { 
       success(...); 
      } 
     } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
      [self downloadFileRetryingNumberOfTimes:ntimes - 1 success:success failure:failure]; 
     }]; 
    } 
} 
+0

我相信这应该是“如果(N次<= 0){如果(故障){...}否则,如果(成功){成功(...):}否则会出现没有反应,如果这是成功的在AFNetworking3.0中 – GK100

+0

AFHTTPRequestOperation已被删除!这个代码应该如何实现与AFNetworking3.0 ???? – do01

2

我在ApiClient类实现私有方法(从马特·汤普森在github上回答):

- (void)sendRequest:(NSURLRequest *)request successBlock:(void (^)(AFHTTPRequestOperation *operation, id responseObject))successBlock failureBlock:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failureBlock 
{ 
    __block NSUInteger numberOfRetries = 3; 
    __block __weak void (^weakSendRequestBlock)(void); 
    void (^sendRequestBlock)(void); 
    weakSendRequestBlock = sendRequestBlock = ^{ 
     __strong typeof (weakSendRequestBlock)strongSendRequestBlock = weakSendRequestBlock; 
     numberOfRetries--; 

     AFHTTPRequestOperation *operation = [self.httpManager HTTPRequestOperationWithRequest:request success:successBlock failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
      NSInteger statusCode = [[[error userInfo] objectForKey:AFNetworkingOperationFailingURLResponseErrorKey] statusCode]; 

      if (numberOfRetries > 0 && (statusCode == 500 || statusCode == 502 || statusCode == 503 || statusCode == 0)) { 
       dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ 
        strongSendRequestBlock(); 
       }); 
      } else { 
       if (failureBlock) { 
        failureBlock(operation, error); 
       } 
      } 
     }]; 

     [self.httpManager.operationQueue addOperation:operation]; 
    }; 

    sendRequestBlock(); 
} 

例用法:

- (void)getSomeDetails:(DictionaryResultBlock)block 
    { 
     if (!block) { 
      return; 
     } 

     NSString *urlString = @"your url string"; 
     NSMutableURLRequest *request = [self.httpManager.requestSerializer requestWithMethod:@"POST" URLString:[[NSURL URLWithString:urlString relativeToURL:self.defaultUrl] absoluteString] parameters:nil error:nil]; 

     // Configure you request here 
     [request setValue:version forHTTPHeaderField:@"client-version"]; 

     NSMutableDictionary *bodyParams = @{}; 
     [request setHTTPBody:[NSJSONSerialization dataWithJSONObject:bodyParams options:0 error:nil]]; 

     [self sendRequest:request successBlock:^(AFHTTPRequestOperation *operation, id responseObject) { 
      id response = [NSJSONSerialization JSONObjectWithData:responseObject options:0 error:nil]; 
      block(response, nil); 
     } failureBlock:^(AFHTTPRequestOperation *operation, NSError *error) { 
      block(nil, error); 
     }]; 
    } 
0

根据您的回答,您可以通过使用块以作为参数块做一些更通用的(和棘手):

typedef void (^CallbackBlock)(NSError* error, NSObject* response); 
- (void) performBlock:(void (^)(CallbackBlock callback)) blockToExecute retryingNumberOfTimes:(NSUInteger)ntimes onCompletion:(void (^)(NSError* error, NSObject* response)) onCompletion { 
    blockToExecute(^(NSError* error, NSObject* response){ 
     if (error == nil) { 
      onCompletion(nil, response); 
     } else { 
      if (ntimes <= 0) { 
       if (onCompletion) { 
        onCompletion(error, nil); 
       } 
      } else { 
       [self performBlock:blockToExecute retryingNumberOfTimes:(ntimes - 1) onCompletion:onCompletion]; 
      } 
     }; 
    }); 
} 

然后环绕你的异步HTTP请求如下所示:

[self performBlock:^(CallbackBlock callback) { 

     [...] 
     AFHTTPRequestOperationManager *manager = [WSManager getHTTPRequestOperationManager]; 
     [manager POST:base parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) { 

      dispatch_async(dispatch_get_main_queue(), ^(void){ 
        if (callback) { 
         callback(nil, responseObject); 
        } 
       }); 

      } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
       if (callback) { 
        NSError* errorCode = [[NSError alloc] initWithDomain:AppErrorDomain code:[operation.response statusCode] userInfo:@{ NSLocalizedDescriptionKey :error.localizedDescription}]; 
        callback(errorCode, nil); 
       } 
      }]; 

    } retryingNumberOfTimes:5 onCompletion:^(NSError *error, NSObject* response) { 
     //everything done 
    }]; 

这样的重试等待HTTP请求完成,你不必实现每个请求方法重试循环。

2

在我的情况,我经常需要重试功能,所以我想出了这个机智重试政策类别,这将有助于你与AFNetworking+RetryPolicy

对于AFNetworking 3.0它可以更好地服务。

+0

这只是史诗般的,究竟是在寻找什么,谢谢! – Tander