2012-08-31 55 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