Question

Mon projet utilise AFNetworking.

https://github.com/AFNetworking/AFNetworking

Comment composer sur le délai d'attente? Atm sans connexion internet fail bloc ne se déclenche pas pour ce qui ressemble à environ 2 minutes. Waay à longue ....

Était-ce utile?

La solution

Modification de l'intervalle de délai d'attente est presque certainement pas la meilleure solution au problème que vous décrivez. Il semble plutôt que ce que vous voulez réellement 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 est perdu la connexion Internet, -setReachabilityStatusChangeBlock:.

Les demandes peut prendre beaucoup de temps sur les réseaux lents. Il est préférable d'iOS de confiance pour savoir comment traiter les connexions lentes, et la différence entre cela et ayant aucun lien.


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

  • Les demandes peuvent être annulées avant qu'ils ne soient même pas commencé. Enqueueing une demande ne donne aucune garantie quant au moment où il commence effectivement.
  • intervalles délai d'attente ne doivent pas annuler des demandes, surtout à long-cours d'exécution du POST. Imaginez si vous essayez de télécharger ou de télécharger une vidéo de 100Mo. Si la demande va ainsi le mieux possible sur un réseau 3G lent, pourquoi vous arrêter inutilement si cela prend un peu plus longtemps que prévu?
  • Faire performSelector:afterDelay:... peut être dangereux dans les applications multi-thread. Cette manière de s'ouvre à obscurcir et les conditions de course difficiles à debug.

Autres conseils

Je recommande vivement regarder la réponse de mattt ci-dessus -., Bien que cette réponse ne mentionne qu'il se heurte pas les problèmes en général, pour les affiches d'origine question, la vérification est joignabilité un ajustement beaucoup mieux

Cependant, si vous ne voulez toujours définir un délai d'attente (sans tous les problèmes inhérents à performSelector:afterDelay: etc, la demande de traction mentionne Lego décrit une façon de le faire comme l'un des commentaires, vous faites juste:

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

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

voir la mise en garde mentionne @KCHarwood de qu'il semble d'Apple ne permet pas à modifier pour les requêtes POST (qui est fixé dans iOS 6 et vers le haut).

Comme @ChrisopherPickslay souligne, ce n'est pas un délai d'attente d'ensemble, il est un délai d'attente entre la réception (ou l'envoi de données). Je ne suis pas au courant d'aucune façon de faire sensiblement un délai d'attente global. La documentation Apple pour dit setTimeoutInterval:

L'intervalle de délai d'attente, en secondes. Si lors d'une tentative de connexion de la demande reste inactif pendant plus longtemps que le délai d'attente, la demande est considéré comme ayant des chronométré. L'intervalle de temporisation par défaut est 60 secondes.

Vous pouvez définir l'intervalle de temporisation par requestSerializer setTimeoutInterval method.You peut obtenir le requestSerializer d'une instance AFHTTPRequestOperationManager.

Par exemple, pour faire une demande de poste avec un délai de 25 secondes:

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

Je pense que vous devez patch manuellement pour le moment.

Je suis le sous-classement AFHTTPClient et a changé le

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

méthode en ajoutant

[request setTimeoutInterval:10.0];

AFHTTPClient.m ligne 236. Bien sûr, il serait bon que cela pourrait être configuré, mais pour autant que je vois ce n'est pas possible à l'heure actuelle.

enfin trouvé comment faire avec une requête POST asynchrone:

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

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

Si vous devez faire une demande synchrone POST, faites Ne pas utiliser [queue waitUntilAllOperationsAreFinished];. Au lieu d'utiliser la même approche que pour la requête asynchrone et attendez que la fonction doit être déclenchée que vous passez dans l'argument de sélection.

D'après les réponses des autres et @ suggestion de mattt sur les questions liées au projet, voici une halte-quickie si vous êtes sous-classement 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

testé pour fonctionner sur iOS 6.

On ne peut pas faire cela avec une minuterie comme ceci:

Dans le fichier .h

{
NSInteger time;
AFJSONRequestOperation *operation;
}

Dans le fichier .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;
}

Il y a deux significations différentes sur la définition de « délai d'attente » ici.

Timeout comme dans timeoutInterval

Vous voulez déposer une demande quand il devient inactif (pas plus de transfert) pendant plus d'un intervalle de temps arbitraire. Exemple: vous définissez timeoutInterval à 10 secondes, vous commencez votre demande à 12:00:00, il peut transférer des données jusqu'à 12:00:23, puis connexion à délai d'attente 12:00:33. Ce cas est couvert par presque toutes les réponses ici (y compris JosephH, Mostafa Abdellateef, Cornelius et Gurpartap Singh).

Timeout comme dans timeoutDeadline

Vous voulez déposer une demande quand il atteint un délai qui se passe plus tard arbitraire. Exemple: vous définissez deadline à 10 secondes à l'avenir, vous commencez votre demande à 12:00:00, il peut tenter de transférer des données jusqu'à 12:00:23, mais la connexion expire au plus tôt à 12:00:10. Ce cas est couvert par borisdiakur.

Je voudrais montrer comment mettre en œuvre cette délai à Swift (3 et 4) pour 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()
}

Et pour donner un exemple testable, ce code devrait imprimer « l'échec » au lieu de « succès » en raison du délai d'attente immédiat à 0.0 secondes dans l'avenir:

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

D'accord avec Matt, vous ne devriez pas essayer de changer le timeoutInterval. Mais vous ne devriez pas compter sur le chèque de joignabilité décider météo tu vas faire le lien, vous ne savez pas jusqu'à ce que vous essayez.

Comme indiqué par le document d'Apple:

En règle générale, vous ne devriez pas utiliser de courts intervalles de temps mort, et à la place, devrait fournir un moyen facile pour l'utilisateur d'annuler une opération de longue durée. Pour plus d'informations, consultez « Conception des réseaux du monde réel ».

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top