7

Google Places API を介して検索バーにオートコンプリートを統合しています。また、ネットワーク リクエストには AFNetworking を使用します。

一度に実行するリクエストは 1 つだけにしたい。そのため、新しい文字を入力するたびに、次のことを行います。

1 - 前の AFHTTPRequestOperation をキャンセルします。

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

2 - 新しい AFHTTPRequestOperation を開始します。

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

リクエストの実行が終了したときに呼び出されるコールバックは次のとおりです。

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

時々私はアサーションにぶつかったので、少し調査したところ、ほとんどのNSURLErrorCancelled場合、期待される動作であるエラー コードで失敗ブロックが呼び出されますが、成功ブロックが呼び出されることもあります。

このスタック トレースは、コード内の処理が正しい順序で行われたことを示しています

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>

isCancelledさらに、成功ブロックが呼び出されたときに AFHTTPRequestOperationのプロパティを見ましたが、 NO が返されます (!!!) NSAssert を使用する代わりにテストするだけで終わる可能性があることはわかっていますが、問題の原因を見つけたいと考えています。

キャンセルしても実際にはリクエストがキャンセルされないという同様の問題に遭遇したことがありますか? そして、失敗ブロックの代わりに成功ブロックが呼び出されますか? これは AFNetworking チームに報告する問題ですか? ありがとう!

それが役立つ場合、リクエストは非常に高速です(GoogleのオートコンプリートAPIは印象的です...)

4

2 に答える 2

1

を調べて、 AFURLConnectionOperation.m の 461 行目をAFNetworkingCode参照してください。

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

表示されている競合状態の唯一の可能性は、操作が既に終了している場合のようです ( [self isFinished])。cancel完了ブロックとの間隔は非常に短い (10 ミリ秒) ことに注意してください。isFinishedリクエストをキャンセルする前に確認できますか?

于 2013-12-22T15:41:51.513 に答える