0

このviewDidLoadを持つtableviewcontrollerを持つアプリがあります:

- (void)viewDidLoad{
    [super viewDidLoad];
    // begin animating the spinner
    [self.spinner startAnimating];

    [SantiappsHelper fetchUsersWithCompletionHandler:^(NSArray *users) {
        self.usersArray = [NSMutableArray array];
        for (NSDictionary *userDict in users) {
            [self.usersArray addObject:[userDict objectForKey:@"username"]];
        }
        //Reload tableview
        [self.tableView reloadData];
    }];
}

ヘルパー クラス メソッドは次のとおりです。

+(void)fetchUsersWithCompletionHandler:(Handler)handler {

    NSString *urlString = [NSString stringWithFormat:@"http://www.myserver.com/myApp/fetchusers.php"];
    NSURL *url = [NSURL URLWithString:urlString];

    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:10];

    [request setHTTPMethod: @"GET"];

    __block NSArray *usersArray = [[NSArray alloc] init];

    //A
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        // Peform the request
        NSURLResponse *response;
        NSError *error = nil;
        NSData *receivedData = [NSURLConnection sendSynchronousRequest:request
                                                     returningResponse:&response
                                                                 error:&error];
        if (error) {
            // Deal with your error
            if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
                NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
                NSLog(@"HTTP Error: %d %@", httpResponse.statusCode, error);
                return;
            }
            NSLog(@"Error %@", error);
            return;
        }

        NSString *responseString = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];

        usersArray = [NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSASCIIStringEncoding] options:0 error:nil];

        if (handler){
            dispatch_async(dispatch_get_main_queue(), ^{
            handler(usersArray);
            });
        }
    });
}

上記のコードは私に提案されたものであり、GCD について私が知っていることから理解できます。すべてがメイン キューで実行されますが、NSURLConnection 同期呼び出しの前にバックグラウンド キューにディスパッチされる前です。データを取得した後、usersArray を満たし、それをメイン キューに返す必要があります。usersArray に値が設定され、if ハンドラーをテストするときに、dispatch_asynch(dispatch_get_main_queue () 行に移動します。しかし、配列辞書を処理するためにメイン キューに戻ると、NSArray *users は空です。このエラーでアプリがクラッシュします。 :

* キャッチされていない例外 'NSInvalidArgumentException' が原因でアプリを終了しています。理由: '* -[__NSArrayM insertObject:atIndex:]: オブジェクトを nil にすることはできません'

dispatch_async(dispatch_get_main_queue() コードをコメントアウトすると、次のようになります。

if (handler){
            //dispatch_async(dispatch_get_main_queue(), ^{
            handler(usersArray);
            //});
        }

それは正常に動作します...まあ、ちょっと遅いです。なぜこれが失敗するのですか?

4

1 に答える 1

1

交換する

dispatch_async(dispatch_get_main_queue(),

と:

dispatch_sync(dispatch_get_main_queue(),

REASON: dispatch_sync は実行前にブロックが完了するのを待ちます

于 2013-07-20T15:06:13.683 に答える