Frage

Mein Projekt verwendet AFNetworking.

https://github.com/afnetworking/afnetworking

Wie wähle ich die Zeitüberschreitung ab? ATM ohne Internetverbindung Der Fail -Block wird nicht für das ausgelöst, was sich wie etwa 2 Minuten anfühlt. Waay bis lang ....

War es hilfreich?

Lösung

Das Ändern des Zeitüberschreitungsintervalls ist mit ziemlicher Sicherheit nicht die beste Lösung für das Problem, das Sie beschreiben. Stattdessen scheint es, als ob der HTTP -Client tatsächlich zu tun ist, dass das Netzwerk nicht erreichbar wird, nein?

AFHTTPClient verfügt bereits über einen integrierten Mechanismus, um Sie mitzuteilen, wann die Internetverbindung verloren geht. -setReachabilityStatusChangeBlock:.

Anfragen können in langsamen Netzwerken lange dauern. Es ist besser, iOS zu vertrauen, wie man langsame Verbindungen umgeht und den Unterschied zwischen dieser und überhaupt keine Verbindung hat.


Um meine Argumentation zu erweitern, warum andere in diesem Thread erwähnte Ansätze vermieden werden sollten, finden Sie hier einige Gedanken:

  • Anfragen können storniert werden, bevor sie überhaupt gestartet werden. Enqueueing Eine Anfrage macht keine Garantien darüber, wann sie tatsächlich beginnt.
  • Zeitüberschreitungsintervalle sollten langlebige Anfragen nicht stornieren-insbesondere nach dem Posten. Stellen Sie sich vor, Sie wollten ein 100 -MB -Video herunterladen oder hochladen. Wenn die Anfrage in einem langsamen 3G -Netzwerk so gut wie möglich geht, warum sollten Sie es dann unnötig stoppen, wenn es etwas länger dauert als erwartet?
  • Tun performSelector:afterDelay:... kann in multi-thread-Anwendungen gefährlich sein. Dies öffnet sich zu dunklen und schwer zu kräuslichen Rassenbedingungen.

Andere Tipps

Ich empfehle dringend, Mattts Antwort oben zu betrachten - obwohl diese Antwort die Probleme, die er im Allgemeinen erwähnt, nicht schlecht fällt. Für die ursprüngliche Poster -Frage ist die Überprüfung der Erreichbarkeit viel besser.

Wenn Sie jedoch immer noch ein Auszeit überlegen möchten (ohne all die Probleme, die inhärent sind performSelector:afterDelay: usw., dann beschreibt die Pull -Anfrage Lego erwähnt einen Weg, dies als einen der Kommentare zu tun. Sie tun es einfach:

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

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

Sehen Sie sich jedoch die Vorbehalt an. @KCharwood erwähnt, dass Apple anscheinend nicht zulässt, dass dies für Postanfragen geändert wird (die in iOS 6 und nach oben festgelegt sind).

Wie @Chrisopherpickslay hervorhebt, ist dies kein Gesamtzeitlimit. Es handelt sich um eine Zeitüberschreitung zwischen Empfang (oder Senden von Daten). Mir ist keine Möglichkeit, vernünftig eine Gesamtzeit zu machen. In der Apple -Dokumentation für SetTimeOutInterval heißt es:

Das Zeitüberschreitungsintervall in Sekunden. Wenn während eines Verbindungsversuchs die Anfrage länger als das Zeitüberschreitungsintervall untätig bleibt, wird angenommen, dass die Anfrage zeitlich festgelegt ist. Das Standard -Timeout -Intervall beträgt 60 Sekunden.

Sie können das Zeitüberschreitungsintervall über RequestSerializer SetTimeOutInterval -Methode einstellen.

Zum Beispiel, um eine Postanforderung mit einer Zeitüberschreitung von 25 Sekunden zu machen:

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

Ich denke, du musst das im Moment manuell einbinden.

Ich subklassige AFHTTPClient und änderte die

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

Methode durch Hinzufügen

[request setTimeoutInterval:10.0];

in Afhttpclient.m Zeile 236. Natürlich wäre es gut, wenn das konfiguriert werden könnte, aber soweit ich sehe, ist das momentan nicht möglich.

Endlich herausgefunden So machen Sie es mit einer asynchronen Postanfrage:

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

Ich habe diesen Code getestet, indem ich meinen Server ließ sleep(aFewSeconds).

Wenn Sie eine synchrone Postanfrage durchführen müssen, tun Sie dies NICHT verwenden [queue waitUntilAllOperationsAreFinished];. Verwenden Sie stattdessen den gleichen Ansatz wie für die asynchrone Anforderung und warten Sie, bis die Funktion ausgelöst wird, die Sie im Selektorargument weitergeben.

Basierend auf den Antworten anderer und dem Vorschlag von @mattts zu verwandten Projektproblemen finden Sie hier ein Drop-In-Quickie, wenn Sie unterklassigen 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

Getestet, um an iOS 6 zu arbeiten.

Können wir das nicht mit einem Timer wie diesem machen:

In .h Datei

{
NSInteger time;
AFJSONRequestOperation *operation;
}

In .m Datei

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

Hier gibt es zwei verschiedene Bedeutungen in der "Timeout" -Definition.

Zeitüberschreitung wie in timeoutInterval

Sie möchten eine Anfrage fallen lassen, wenn sie länger als ein willkürliches Zeitintervall im Leerlauf wird (nicht mehr Übertragung). Beispiel: Sie haben festgelegt timeoutInterval Bis zu 10 Sekunden starten Sie Ihre Anfrage um 12:00:00 Uhr, sie kann einige Daten bis 12:00:23 übertragen, und die Verbindung wird um 12:00:33 Uhr ausgeschieden. Dieser Fall wird von fast allen Antworten hier abgedeckt (einschließlich Josephh, Mostafa Abdellateef, Cornelius und Gurpartap Singh).

Zeitüberschreitung wie in timeoutDeadline

Sie möchten eine Anfrage fallen lassen, wenn sie später eine Frist einleitet. Beispiel: Sie haben festgelegt deadline Zu 10 Sekunden in der Zukunft starten Sie Ihre Anfrage um 12:00:00 Uhr. Sie kann versuchen, einige Daten bis 12:00:23 zu übertragen, aber die Verbindung wird früher um 12:00:10 Uhr einreichen. Dieser Fall wird von Borisdiakur abgedeckt.

Ich möchte zeigen, wie man das implementiert Termin in Swift (3 und 4) für 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()
}

Und um ein prüfbares Beispiel zu geben, sollte dieser Code "Fehler" anstelle von "Erfolg" drucken

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

Stimmen Sie Matt zu, Sie sollten nicht versuchen, das TimeoutInterval zu ändern. Sie sollten sich aber auch nicht auf die Erreichbarkeitsprüfung verlassen, um das Wetter zu entscheiden, dass Sie die Verbindung herstellen. Sie wissen es nicht, bis Sie es versuchen.

Wie von Apple Dokument angegeben:

In der Regel sollten Sie keine kurzen Zeitüberschreitungsintervalle verwenden und stattdessen eine einfache Möglichkeit für den Benutzer bieten, einen langjährigen Betrieb abzubrechen. Weitere Informationen finden Sie unter „Entwerfen für reale Netzwerke“.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top