[objective-c] AFNetworking으로 시간 제한을 설정하는 방법

내 프로젝트는 AFNetworking을 사용하고 있습니다.

https://github.com/AFNetworking/AFNetworking

시간 제한을 어떻게 줄입니까? 인터넷에 연결되지 않은 ATM에서는 약 2 분 동안 실패 블록이 트리거되지 않습니다. 오래 기다려 ….



답변

제한 시간 간격을 변경하는 것은 설명하는 문제에 대한 최선의 해결책이 아닙니다. 대신, 실제로 원하는 것은 HTTP 클라이언트가 네트워크에 연결할 수 없게되는 것을 처리하는 것입니다.

AFHTTPClient이미 인터넷 연결이 끊어졌을 때 알려주는 내장 메커니즘이 있습니다 -setReachabilityStatusChangeBlock:.

느린 네트워크에서는 요청에 오랜 시간이 걸릴 수 있습니다. 느린 연결을 처리하는 방법을 알고 연결이 전혀없는 것과 그 차이를 알리려면 iOS를 신뢰하는 것이 좋습니다.


이 스레드에 언급 된 다른 접근 방식을 피해야하는 이유에 대한 내 추론을 확장하기 위해 다음과 같은 몇 가지 생각이 있습니다.

  • 요청은 시작되기 전에 취소 할 수 있습니다. 요청을 대기열에 넣는 것은 실제로 시작되는시기를 보장하지 않습니다.
  • 시간 초과 간격은 장기 실행 요청, 특히 POST를 취소해서는 안됩니다. 100MB 비디오를 다운로드하거나 업로드하려고한다고 상상해보십시오. 요청이 느린 3G 네트워크에서 가능한 한 최선을 다한다면 예상보다 조금 더 오래 걸리면 왜 불필요하게 중지 하시겠습니까?
  • 이렇게하면 performSelector:afterDelay:...멀티 스레드 애플리케이션에 위험 할 수 있습니다. 이것은 모호하고 디버그하기 어려운 경쟁 조건에 자신을 열어줍니다.


답변

위의 mattt의 답변을 살펴볼 것을 강력히 권장합니다.이 답변은 그가 일반적으로 언급하는 문제에 해당하지 않지만 원래 포스터 질문의 경우 도달 가능성을 확인하는 것이 훨씬 더 적합합니다.

그러나 여전히 타임 아웃을 설정하고 싶다면 ( performSelector:afterDelay:등에 내재 된 모든 문제없이) 풀 리퀘스트 레고가 언급 한 주석 중 하나로이를 수행하는 방법을 설명합니다.

NSMutableURLRequest *request = [client requestWithMethod:@"GET" path:@"/" parameters:nil];
[request setTimeoutInterval:120];

AFHTTPRequestOperation *operation = [client HTTPRequestOperationWithRequest:request success:^{...} failure:^{...}];
[client enqueueHTTPRequestOperation:operation];

그러나 @KCHarwood는 Apple이 POST 요청 (iOS 6 이상에서 수정 됨)에 대한 변경을 허용하지 않는 것으로 보인다는 경고를 참조하십시오.

@ChrisopherPickslay가 지적했듯이 이것은 전체 시간 제한이 아니라 데이터 수신 (또는 전송) 사이의 시간 제한입니다. 전체 시간 제한을 현명하게 수행하는 방법을 알지 못합니다. setTimeoutInterval에 대한 Apple 문서는 다음과 같이 말합니다.

시간 초과 간격 (초)입니다. 연결을 시도하는 동안 요청이 시간 초과 간격보다 오랫동안 유휴 상태로 유지되면 요청이 시간 초과 된 것으로 간주됩니다. 기본 시간 초과 간격은 60 초입니다.


답변

requestSerializer setTimeoutInterval 메서드를 통해 제한 시간 간격을 설정할 수 있으며 AFHTTPRequestOperationManager 인스턴스에서 requestSerializer를 가져올 수 있습니다.

예를 들어 시간 제한이 25 초인 게시 요청을 수행하려면 다음을 수행하십시오.

    NSDictionary *params = @{@"par1": @"value1",
                         @"par2": @"value2"};

    AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];

    [manager.requestSerializer setTimeoutInterval:25];  //Time out after 25 seconds

    [manager POST:@"URL" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {

    //Success call back bock
    NSLog(@"Request completed with response: %@", responseObject);


    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
     //Failure callback block. This block may be called due to time out or any other failure reason
    }];


답변

지금은 수동으로 패치해야한다고 생각합니다.

AFHTTPClient를 서브 클래 싱하고 있으며

- (NSMutableURLRequest *)requestWithMethod:(NSString *)method path:(NSString *)path parameters:(NSDictionary *)parameters

추가하는 방법

[request setTimeoutInterval:10.0];

AFHTTPClient.m의 그 구성 할 수 있다면 물론 라인 (236)은 좋은 것입니다,하지만 지금까지 나는 그 순간에 불가능하다 볼 수있다.


답변

마지막으로 비동기 POST 요청으로 수행하는 방법을 찾았습니다 .

- (void)timeout:(NSDictionary*)dict {
    NDLog(@"timeout");
    AFHTTPRequestOperation *operation = [dict objectForKey:@"operation"];
    if (operation) {
        [operation cancel];
    }
    [[AFNetworkActivityIndicatorManager sharedManager] decrementActivityCount];
    [self perform:[[dict objectForKey:@"selector"] pointerValue] on:[dict objectForKey:@"object"] with:nil];
}

- (void)perform:(SEL)selector on:(id)target with:(id)object {
    if (target && [target respondsToSelector:selector]) {
        [target performSelector:selector withObject:object];
    }
}

- (void)doStuffAndNotifyObject:(id)object withSelector:(SEL)selector {
    // AFHTTPRequestOperation asynchronous with selector                
    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:
                            @"doStuff", @"task",
                            nil];

    AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:[NSURL URLWithString:baseURL]];

    NSMutableURLRequest *request = [httpClient requestWithMethod:@"POST" path:requestURL parameters:params];
    [httpClient release];

    AFHTTPRequestOperation *operation = [[[AFHTTPRequestOperation alloc] initWithRequest:request] autorelease];

    NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:
                          operation, @"operation",
                          object, @"object",
                          [NSValue valueWithPointer:selector], @"selector",
                          nil];
    [self performSelector:@selector(timeout:) withObject:dict afterDelay:timeout];

    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(timeout:) object:dict];
        [[AFNetworkActivityIndicatorManager sharedManager] decrementActivityCount];
        [self perform:selector on:object with:[operation responseString]];
    }
    failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        NDLog(@"fail! \nerror: %@", [error localizedDescription]);
        [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(timeout:) object:dict];
        [[AFNetworkActivityIndicatorManager sharedManager] decrementActivityCount];
        [self perform:selector on:object with:nil];
    }];

    NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
    [[AFNetworkActivityIndicatorManager sharedManager] incrementActivityCount];
    [queue addOperation:operation];
}

내 서버를 허용하여이 코드를 테스트했습니다 sleep(aFewSeconds).

동기 POST 요청을 수행해야하는 경우를 사용 하지 마십시오[queue waitUntilAllOperationsAreFinished]; . 대신 비동기 요청과 동일한 접근 방식을 사용하고 selector 인수에서 전달하는 함수가 트리거 될 때까지 기다립니다.


답변

관련 프로젝트 문제에 대한 다른 사람의 답변과 @mattt의 제안을 기반으로하여 서브 클래 싱하는 경우 드롭 인 빠른 방법이 있습니다 AFHTTPClient.

@implementation SomeAPIClient // subclass of AFHTTPClient

// ...

- (NSMutableURLRequest *)requestWithMethod:(NSString *)method path:(NSString *)path parameters:(NSDictionary *)parameters {
  NSMutableURLRequest *request = [super requestWithMethod:method path:path parameters:parameters];
  [request setTimeoutInterval:120];
  return request;
}

- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method path:(NSString *)path parameters:(NSDictionary *)parameters constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block {
  NSMutableURLRequest *request = [super requestWithMethod:method path:path parameters:parameters];
  [request setTimeoutInterval:120];
  return request;
}

@end

iOS 6에서 작동하도록 테스트되었습니다.


답변

다음과 같은 타이머로이 작업을 수행 할 수 없습니다.

.h 파일

{
NSInteger time;
AFJSONRequestOperation *operation;
}

.m 파일

-(void)AFNetworkingmethod{

    time = 0;

    NSTtimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(startTimer:) userInfo:nil repeats:YES];
    [timer fire];


    operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
        [self operationDidFinishLoading:JSON];
    } failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {
        [self operationDidFailWithError:error];
    }];
    [operation setJSONReadingOptions:NSJSONReadingMutableContainers];
    [operation start];
}

-(void)startTimer:(NSTimer *)someTimer{
    if (time == 15&&![operation isFinished]) {
        time = 0;
        [operation invalidate];
        [operation cancel];
        NSLog(@"Timeout");
        return;
    }
    ++time;
}