79 votes

Comment définir un délai d'attente avec AFNetworking

Mon projet est à l'aide de AFNetworking.

https://github.com/AFNetworking/AFNetworking

Comment puis-je composer le délai d'attente? Atm avec aucune connexion internet n'bloc n'est pas déclenché pour ce qui ressemble à environ 2 minutes. Waay pour longtemps....

109voto

mattt Points 10419

Modification de l'intervalle de délai d'attente est presque certainement pas la meilleure solution pour le problème que vous décrivez. Au lieu de cela, il semble que ce que vous voulez vraiment est pour le client HTTP pour gérer le réseau devient inaccessible, non?

AFHTTPClient a déjà un mécanisme intégré pour vous permettre de savoir quand la connexion internet est perdue, -setReachabilityStatusChangeBlock:.

Demandes peut prendre un long moment sur les réseaux lents. Il est préférable de faire confiance à iOS pour savoir comment gérer les connexions lentes, et de faire la différence entre cela et ayant pas de connexion du tout.


Pour développer mon raisonnement pour expliquer pourquoi d'autres approches citées dans ce fil devrait être évitée, voici quelques réflexions:

  • Une demande peut être annulée avant même d'avoir commencé. Enqueueing une demande ne garantit pas, quand il commence réellement.
  • Intervalles de délai d'attente ne devrait pas annuler long demandes en cours d'exécution-notamment après. Imaginez si vous étiez en train de télécharger ou de télécharger une vidéo de 100 mo. Si la demande se passe du mieux qu'il peut sur un lent réseau 3G, pourquoi voudriez-vous inutilement l'arrêter s'il est un peu plus long que prévu?
  • Faire performSelector:afterDelay:... peut être dangereux dans des applications multi-thread. Cela ouvre soi-même jusqu'à obscures et difficiles à déboguer des conditions de course.

43voto

JosephH Points 21074

Je recommande fortement de regarder mattt la réponse ci-dessus - bien que cette réponse ne tombe pas sous le coup de les problèmes il mentionne en général, pour les affiches originales question, la vérification de l'accessibilité est un bien meilleur ajustement.

Toutefois, si vous ne voulez toujours définir un délai d'attente (sans tous les problèmes inhérents à l' performSelector:afterDelay: etc, alors que la demande de pull Lego mentionne décrit une manière de faire ce que l'un des commentaires, il suffit de le faire:

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

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

mais voir la mise en garde @KCHarwood mentionne qu'il semble que Apple ne permettent pas que cela soit changé pour les requêtes POST (qui est fixe dans iOS 6 et plus).

@ChrisopherPickslay points, ce n'est pas une temporisation globale, c'est un délai d'attente entre la réception (ou l'envoi de données). Je ne suis pas au courant de toute façon intelligemment faire une temporisation globale. La documentation d'Apple pour setTimeoutInterval dit:

L'intervalle de délai d'attente, en secondes. Si au cours d'une tentative de connexion l' la demande reste inactif pendant plus longtemps que l'intervalle de délai d'attente, la demande est considérée comme ayant expiré. La valeur par défaut intervalle de délai d'attente est de 60 secondes.

26voto

Vous pouvez définir l'intervalle de délai d'attente par le biais de requestSerializer setTimeoutInterval méthode.Vous pouvez obtenir le requestSerializer à partir d'un AFHTTPRequestOperationManager instance.

Par exemple, pour faire une requête post avec un délai d'attente de 25 seconde :

    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
    }];

7voto

Cornelius Points 1096

Je pense que vous devez patch manuellement pour le moment.

Je suis sous-classement AFHTTPClient et changé le

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

méthode en ajoutant

[request setTimeoutInterval:10.0];

dans AFHTTPClient.m de la ligne 236. Bien sûr, ce serait bien si ça pouvait être configuré, mais aussi loin que je vois ce n'est pas possible pour le moment.

7voto

borisdiakur Points 3547

Enfin trouvé comment le faire avec un asynchrones requête 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];
}

J'ai testé ce code en laissant mon serveur sleep(aFewSeconds).

Si vous avez besoin de faire un synchrones requête POST, ne PAS utiliser [queue waitUntilAllOperationsAreFinished];. Au lieu d'utiliser la même approche pour la requête asynchrone et d'attendre pour que la fonction puisse être déclenchée que vous lui transmettez dans le sélecteur d'argument.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by: