web-dev-qa-db-ja.com

メインスレッドでNSURLSession完了ハンドラーを実行する

NSURLSessionを使用して、TableViewに入力する値を取得しています。完了ハンドラーでTableViewを更新していますが、[[NSThread currentThread] isMainThread]を使用すると、完了ハンドラーがメインスレッドで実行されていないことがわかりました。メインスレッドからUIを更新するだけなので、これは正しくないことがわかります。完了ハンドラーからメインスレッドでアクションをトリガーする方法はありますか?または、NSURLSessionを使用してこれを行う間違った方法ですか?

NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:[NSURL URLWithString:@"http://myurl"]
        completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
            NSError *jsonError = nil;
            NSArray* jsonUsers = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
            if (jsonError) {
                NSLog(@"error is %@", [jsonError localizedDescription]);
                // Handle Error and return
                return;
            }
            self.userArray = jsonUsers;
            [self.userTableView reloadData];
            if ([[NSThread currentThread] isMainThread]){
                NSLog(@"In main thread--completion handler");
            }
            else{
                NSLog(@"Not in main thread--completion handler");
            }
}] resume];
24
otter

はい、GCDを使用してメインスレッドをディスパッチします。

 NSURLSession *session = [NSURLSession sharedSession];
    [[session dataTaskWithURL:[NSURL URLWithString:@"http://myurl"]
            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                NSError *jsonError = nil;
                NSArray* jsonUsers = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
                if (jsonError) {
                    NSLog(@"error is %@", [jsonError localizedDescription]);
                    // Handle Error and return
                    return;
                }

                dispatch_async(dispatch_get_main_queue(), ^{
                    self.userArray = jsonUsers;
                    [self.userTableView reloadData];
                    if ([[NSThread currentThread] isMainThread]){
                        NSLog(@"In main thread--completion handler");
                    }
                    else{
                        NSLog(@"Not in main thread--completion handler");
                    }
                });

            }] resume];
41
graver

@graverの答えは良いです。これを行う別の方法を次に示します。

NSURLSession* session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
                                                          delegate:nil
                                                     delegateQueue:[NSOperationQueue mainQueue]];
[[session dataTaskWithURL:[NSURL URLWithString:@"http://myurl"]
        completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
            NSError *jsonError = nil;
            NSArray* jsonUsers = [NSJSONSerialization JSONObjectWithData:data options:0 error:&jsonError];
            if (jsonError) {
                NSLog(@"error is %@", [jsonError localizedDescription]);
                // Handle Error and return
                return;
            }

            self.userArray = jsonUsers;
            [self.userTableView reloadData];
            if ([[NSThread currentThread] isMainThread]){
                NSLog(@"In main thread--completion handler");
            }
            else{
                NSLog(@"Not in main thread--completion handler");
            }
        }] resume];

このようにして、メインスレッドで完了ブロックとデリゲートメソッドを呼び出すセッションを作成します。あなたはこれをより審美的に楽しいと感じるかもしれませんが、あなたはバックグラウンドで「ハードワーク」を実行する利点を失います。

18
bugloaf

これを試すことができます:

[self.userTableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
3
Big-O Claire

ブロックと完了ハンドラーからUIを更新する最良の方法は次のとおりです。また、コードを実行しているスレッドが不明な場合も同様です。

static void runOnMainThread(void (^block)(void))
{
    if (!block) return;

    if ( [[NSThread currentThread] isMainThread] ) {
        block();
    } else {
        dispatch_async(dispatch_get_main_queue(), block);
    }
}

これはブロックを持ち、メインスレッドで実行される静的メソッドです。

runOnMainThread(^{
           // do things here, it will run on main thread, like updating UI

        });
3
Adnan Aftab

Swift 3.1

DispatchQueue.main.async {
    tableView.reloadData()
}
0
William Hu

完了時に通知を送信します。この通知は、Table View Controllerによって監視され、reloadDataを実行します。

これには、後でこのダウンロードコードを別のクラスに移動した場合などの利点があります。モデルオブジェクトの場合、変更は不要です。また、コードを変更せずに他のプロジェクトで再利用できます。

0
SPA