Вопрос

Мой проект использует Afnetworking.

https://github.com/afnetworking/afnetworking

Как мне набрать тайм -аут? Атм без подключения к Интернету Блок Fail не запускается для того, что кажется около 2 минут. Ваай до долго ....

Это было полезно?

Решение

Изменение интервала тайм -аута почти наверняка - не лучшее решение проблемы, которую вы описываете. Вместо этого, кажется, что вы на самом деле хотите, чтобы клиент HTTP обрабатывал сеть, которая становится недоступной, не так ли?

AFHTTPClient Уже есть встроенный механизм, чтобы сообщить вам, когда интернет-соединение потеряно, -setReachabilityStatusChangeBlock:.

Запросы могут занять много времени в медленных сетях. Лучше доверять iOS, чтобы узнать, как иметь медленные связи, и сказать разницу между этим и вообще не имея связи.


Чтобы расширить мои рассуждения относительно того, почему следует избегать других подходов, упомянутых в этой теме, вот несколько мыслей:

  • Запросы могут быть отменены еще до того, как они начнут. Внесение запроса не дает никаких гарантий о том, когда он на самом деле начинается.
  • Интервалы тайм-аута не должны отменять длительные запросы, особенно публиковать. Представьте себе, если вы пытались загрузить или загрузить видео 100 МБ. Если запрос идет как можно лучше в медленной сети 3G, зачем вам без необходимости останавливать его, если он занимает немного больше времени, чем ожидалось?
  • Делает performSelector:afterDelay:... может быть опасным в многопоточных приложениях. Это открывается для неясных и труднодоступных условий гонки.

Другие советы

Я настоятельно рекомендую взглянуть на ответ Мэтта выше - хотя этот ответ не нарушает проблемы, которые он в целом упоминает, для вопроса о оригинальном плакатах проверка достижимости намного лучше подходит.

Однако, если вы все еще хотите установить тайм -аут (без всех проблем, присущих в performSelector:afterDelay: и т. Д., Тогда упоминание LEGO в обращении описывает способ сделать это как один из комментариев, вы просто делаете:

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, это не общий тайм -аут, это тайм -аут между получением (или отправкой данных). Я не знаю, как разумно сделать общий тайм -аут. В документации Apple для SetTimeOutInterval говорится:

Интервал тайм -аута, в секунды. Если во время попытки подключения запрос остается бездействующим дольше, чем интервал тайм -аута, считается, что запрос был рассчитано. Интервал тайм -аута по умолчанию составляет 60 секунд.

Вы можете установить интервал тайм -аута с помощью метода SetTimeUnterval SetTimeUnterval.

Например, чтобы сделать запрос на сообщение с тайм -аутом 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. Конечно было бы хорошо, если бы это было бы настроено, но, насколько я вижу, это невозможно в данный момент.

Наконец узнал Как сделать это с помощью асинхронного запроса поста:

- (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).

Если вам нужно сделать синхронный запрос пост, сделайте НЕТ использовать [queue waitUntilAllOperationsAreFinished];. Анкет Вместо этого используйте тот же подход, что и для асинхронного запроса, и дождитесь запуска функции, которую вы передаете в аргументе селектора.

Основываясь на ответах других и предложении @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;
}

Здесь есть два разных значения в определении «Тайм -аут».

Тайм -аут, как в timeoutInterval

Вы хотите отказаться от запроса, когда он становится холодным (не больше передачи) дольше, чем произвольный интервал времени. Пример: вы устанавливаете timeoutInterval В 10 секунд вы начинаете свой запрос в 12:00:00, он может передавать некоторые данные до 12:00:23, затем подключение будет время ожидания в 12:00:33. Этот случай покрывается почти всеми ответами здесь (включая Джозефх, Мостафа Абделлатеф, Корнелиуса и Гурпартапа Сингха).

Тайм -аут, как в timeoutDeadline

Вы хотите отказаться от запроса, когда он достигнет крайнего срока, произошедшего произвольным позже. Пример: вы устанавливаете deadline До 10 секунд в будущем вы начинаете свой запрос в 12:00:00, он может попытаться передавать некоторые данные до 12:00:23, но подключение будет время ожидания ранее в 12:00:10. Этот случай покрывается Борисдиакуром.

Я хотел бы показать, как это реализовать срок В Swift (3 и 4) для Afnetworking 3.1.

let sessionManager = AFHTTPSessionManager(baseURL: baseURL)
let request = sessionManager.post(endPoint, parameters: parameters, progress: { ... }, success: { ... }, failure: { ... })
// timeout deadline at 10 seconds in the future
DispatchQueue.global().asyncAfter(deadline: .now() + 10.0) {
    request?.cancel()
}

И чтобы привести тестируемый пример, этот код должен печатать «сбой» вместо «успеха» из -за непосредственного тайм -аута на 0,0 секунды в будущем:

let sessionManager = AFHTTPSessionManager(baseURL: URL(string: "https://example.com"))
sessionManager.responseSerializer = AFHTTPResponseSerializer()
let request = sessionManager.get("/", parameters: nil, progress: nil, success: { _ in
    print("success")
}, failure: { _ in
    print("failure")
})
// timeout deadline at 0 seconds in the future
DispatchQueue.global().asyncAfter(deadline: .now() + 0.0) {
    request?.cancel()
}

Согласитесь с Мэттом, вы не должны пытаться менять TimeoutInterval. Но вы также не должны полагаться на проверку досягаемости, чтобы решить погоду, вы собираетесь установить связь, вы не знаете, пока не попробуете.

Как указано в Apple Document:

Как правило, вы не должны использовать короткие интервалы тайм-аута, а вместо этого должны предоставить пользователю простой способ отменить длительную работу. Для получения дополнительной информации прочитайте «Проектирование для реальных сетей».

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top