2013-12-22 11 views
7

Ich integriere Autocomplete über Google Places API in eine Suchleiste. Und für die Netzwerkanforderungen verwende ich AFNetworking.Warum abgebrochen AFHTTPRequestOperation manchmal den Erfolgsblock getroffen?

Ich möchte nur eine Anfrage gleichzeitig ausführen lassen. Also jedes Mal tippe ich einen neuen Brief, ich folgendes:

1 - Abbrechen des vorherigen AFHTTPRequestOperation:

[self.currentGlobalSearchListRequest cancel]; 
NSLog(@"%@ cancelled", self.currentGlobalSearchListRequest); 

2 - Starten Sie ein neues AFHTTPRequestOperation:

self.currentGlobalSearchListRequest = [searchService getGlobalSearchListItemsForString:searchString inRegion:region delegate:self]; 
NSLog(@"%@ started", self.currentGlobalSearchListRequest); 

Hier ist der Rückruf aufgerufen wenn die Anfrage beendet ist:

- (void)request:(PointSearchRequest *)request didLoadSearchListItems:(NSArray *)searchListItems { 
    NSAssert(request == self.currentGlobalSearchListRequest, @"!!!callback from a request that should be cancelled!!!"); 
    [self.delegate searchListLoader:self didLoadGlobalSearchList:searchListItems]; 
} 

Manchmal traf ich die Behauptung Ich habe also ein wenig untersucht und festgestellt, dass der Fehlerblock mit einem Fehlercode NSURLErrorCancelled aufgerufen wird, was das erwartete Verhalten ist, aber manchmal wird der Erfolgsblock aufgerufen!

Dieser Stack-Trace sagt mir, dass die Dinge in meinem Code in der richtigen Reihenfolge aufgetreten

2013-12-22 09:38:46.484 Point[63595:a0b] <PointSearchRequest: 0x18202b50> started 
2013-12-22 09:38:46.486 Point[63595:a0b] <PointSearchRequest: 0x18202b50> cancelled 
2013-12-22 09:38:46.487 Point[63595:a0b] <PointSearchRequest: 0x181a5dd0> started 
2013-12-22 09:38:46.496 Point[63595:a0b] *** Assertion failure in -[SearchListLoader request:didLoadSearchListItems:], /Users/aurelienporte/Documents/Developpement/Perso/iOS/Point/Point/Classes/Models/SearchListLoader.m:82 
(lldb) po request 
<PointSearchRequest: 0x18202b50> 

Plus schaute ich auf die Eigenschaft isCancelled auf AFHTTPRequestOperation, wenn der Erfolg Block genannt wird, aber es gibt mir NEIN (!!!) Ich weiß, ich könnte am Ende nur testen statt mit NSAssert, aber möchte den Ursprung des Problems finden.

Sind Sie schon einmal auf ähnliche Probleme gestoßen, bei denen Abbrechen die Anfrage nicht abbricht? Und dann wird der Erfolgsblock anstelle des Fehlerblocks aufgerufen? Ist dies ein Problem, das dem AFNetworking-Team gemeldet werden muss? Danke!

Wenn es helfen kann, die Anforderungen schnell flippen (Google Autocomplete aPI beeindruckend ...)

+0

Ich würde dies erwarten. Das Abbrechen einer abgeschlossenen Operation, die ihren Beendigungshandler nicht ausgelöst hat, ist mehrdeutig; es könnte entweder den Beendigungshandler auslösen oder den Abbruch akzeptieren. Ich würde nicht darauf zählen, dass es zu 100% passiert. –

Antwort

1

in AFNetworkingCode Sehen, siehe AFURLConnectionOperation.m, line 461

- (void)cancel { 
    [self.lock lock]; 
    if (![self isFinished] && ![self isCancelled]) { 
     [super cancel]; 

     if ([self isExecuting]) { 
      [self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]]; 
     } 
    } 
    [self.lock unlock]; 
} 

Es scheint, dass die einzige Möglichkeit für die Race-Bedingung der Fall, dass Sie sehen, ist, wenn der Vorgang bereits abgeschlossen worden ist ([self isFinished]). Beachten Sie, dass das Intervall zwischen Ihrem cancel und dem Abschlussblock sehr klein ist (10 ms). Vielleicht könnten Sie isFinished überprüfen, bevor Sie versuchen, die Anfrage abzubrechen?

+0

Ich schaute dies an und in der Tat ist die Operation in den Situationen beendet, in denen mein NSAssert ausgelöst wird. Vielen Dank. Dies bedeutet, dass zwischen der Zeit, in der 'isFinished 'auf YES gesetzt ist, und der Zeit, zu der die Erfolgs- oder Fehlerblockierung zurückgerufen wird, eine Verzögerung auftritt. Ich nehme an, es liegt daran, dass diese zwei "Momente" nicht im selben Thread vorkommen, oder? –

+1

@ AurelienPorte Ja. 'NSOperation' sollte fast sofort' completionBlock' aufrufen, aber es gibt zwei weitere 'dispatch_async' bevor der Erfolgs- oder Fehlerblock aufgerufen wird. Jedes 'dispatch_async' verschiebt die Ausführung ein wenig. Das liegt daran, dass AFNetworking mehrere Dispatch-Warteschlangen verwendet und die Ausführung alle durchlaufen muss, bevor Sie Ihren Erfolgsblock erreichen. – Sulthan

0

Wie wir alle wissen, wird eine Thread-Funktion geht nicht, obwohl Sie den Faden in der Mitte abbrechen, wenn es Starten Sie, es wird die Methode vervollständigen. So wie die Anfrage. Das heißt, wenn sich die Anforderung noch in der NSOperationQueue befindet, können Sie sie abbrechen, aber solange Sie die Operation als Summit ausführen und der Block eine Kopie ist, ruft sie zurück.

Wenn Sie den Rückruf nicht annehmen möchten, können Sie einfach im Rückruf sagen, ob die Anfrage abgebrochen wird.

Ich hoffe, dass es Ihnen helfen wird.

+0

Danke. Ich stimme dem allgemeinen Fall zu.Und dies sollte von der AFNetworking-Bibliothek selbst gehandhabt werden, so dass es mein Fehlerblock ist, der aufgerufen werden sollte. –

Verwandte Themen