2

NSURLConnection複数の非同期リクエストを行うために使用しています。進行状況インジケーターを表示して、実行する合計数のうち、完了したリクエストの数を示したいと思います。ただし、リクエストを行う前に、またはリクエストを実行する前に呼び出される別のメソッドで、この進行状況インジケーターを設定して表示しようとすると、表示されません。リクエストがコメントアウトされている場合、進行状況インジケーターは正常に表示されます。しかし、そうでない場合は、Xcode が先を見越して非同期リクエストが来ることを確認し、メイン スレッドをブロックして、UI の変更を不可能にしているように見えます。

進行状況インジケーターを表示するための要求とコードの両方を含む、呼び出される関連コードを次に示します。

- (void)getRegionalInformationFromChecked:(NSSet *)set atIndex:(NSInteger)index {
    __block BOOL responseRecieved = NO;
    NSString *stringForURL = [NSString stringWithFormat:@"http://www.thebluealliance.com/api/v1/event/details?event=%@",[[set allObjects] objectAtIndex:index]];
    NSURL *url = [NSURL URLWithString:stringForURL];
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    NSLog(@"URL IS GO: %@", stringForURL);
    [NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:url] queue:queue completionHandler:^(NSURLResponse *_response, NSData *_data, NSError *_error) {
    NSLog(@"CHECKED DATA RETURNED AT INDEX %i", index);
    NSError *error;
    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:_data options:NSJSONReadingMutableContainers error:&error];
    if (!_regionalDetails) {
        _regionalDetails = [[NSMutableArray alloc] init];
    }
    [_regionalDetails addObject:dict];
    responseRecieved = YES;
}];
    regionalSchedulesToGet = [set count];
    while (responseRecieved == NO) {}
    [[MBProgressHUD HUDForView:[[UIApplication sharedApplication] keyWindow]] setLabelText:[NSString stringWithFormat: @"Getting regional %i of %i", index+2, [set count]]];
    if (index+1 < [set count]) {
        [self getRegionalInformationFromChecked:set atIndex:index+1];
    } else {
        [[MBProgressHUD HUDForView:[[UIApplication sharedApplication] keyWindow]] setLabelText:@"Writing to file"];
    }
}

非同期リクエストのブロックがコメントアウトされている場合、MBProgressHUDはその値を正常に表示します。ただし、ブロックが挿入されると、SDK は、ブロックを離れた後でも進行状況インジケーターの更新を拒否します (その後、スレッドの問題は解決されているはずです)。表示する要求がなくなるまで更新されず、その時点で「ファイルへの書き込み」と表示されます。

非同期リクエストがメイン スレッドをブロックしているように見えるのはなぜですか? また、リクエストが呼び出される直前または直後にメイン スレッドを変更できないのはなぜですか?

4

2 に答える 2

5

while (responseRecieved == NO) {}

非同期ブロックが完了するまで、(おそらくほぼ 100% の CPU 負荷で) メイン スレッドをブロックします。次に、関数を再帰的に呼び出し、別の非同期ブロックを開始し、それが完了するまで再度ブロックします。したがって、すべての 操作が完了するまで、プログラム制御はメインの実行ループに戻りません。その後、UI の更新が行われます。

同期的に待機するのではなく (これは常に悪い考えです)、完了ブロックの最後で次の操作を開始する必要があります。

queueの引数はsendAsynchronousRequest、完了ハンドラが呼び出されるキューであるため、そのまま使用できることにも注意してください[NSOperationQueue mainQueue]

次に、コードはおおよそ次のようになります。

- (void)getRegionalInformationFromChecked:(NSSet *)set atIndex:(NSInteger)index
{
    [[MBProgressHUD HUDForView:[[UIApplication sharedApplication] keyWindow]]
     setLabelText:[NSString stringWithFormat:@"Getting regional %i of %i", index+1, [set count]]];
    NSString *stringForURL = [NSString stringWithFormat:@"http://www.thebluealliance.com/api/v1/event/details?event=%@",[[set allObjects] objectAtIndex:index]];
    NSURL *url = [NSURL URLWithString:stringForURL];
    NSLog(@"URL IS GO: %@", stringForURL);
    [NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:url] queue:[NSOperationQueue mainQueue]
                           completionHandler:^(NSURLResponse *_response, NSData *_data, NSError *_error) {
        NSLog(@"CHECKED DATA RETURNED AT INDEX %i", index);
        NSError *error;
        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:_data options:NSJSONReadingMutableContainers error:&error];
        if (!_regionalDetails) {
            _regionalDetails = [[NSMutableArray alloc] init];
        }
        [_regionalDetails addObject:dict];
        if (index+1 < [set count]) {
            [self getRegionalInformationFromChecked:set atIndex:index+1];
        } else {
            [[MBProgressHUD HUDForView:[[UIApplication sharedApplication] keyWindow]] setLabelText:@"Writing to file"];
            // ... perhaps call a completion function from here ?
        }
    }];
}

ただし、 への最初の呼び出しはgetRegionalInformationFromCheckedほぼすぐに返されることに注意してください (これが非同期タスクのしくみです :-)。

于 2013-04-20T19:56:41.717 に答える
-2

UI の更新を伴うすべてのメソッドをメイン スレッドでディスパッチするようにしてください。

于 2013-04-20T19:49:35.443 に答える