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];
はい、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];
@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];
このようにして、メインスレッドで完了ブロックとデリゲートメソッドを呼び出すセッションを作成します。あなたはこれをより審美的に楽しいと感じるかもしれませんが、あなたはバックグラウンドで「ハードワーク」を実行する利点を失います。
これを試すことができます:
[self.userTableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
ブロックと完了ハンドラーから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
});
Swift 3.1
DispatchQueue.main.async {
tableView.reloadData()
}
完了時に通知を送信します。この通知は、Table View Controllerによって監視され、reloadDataを実行します。
これには、後でこのダウンロードコードを別のクラスに移動した場合などの利点があります。モデルオブジェクトの場合、変更は不要です。また、コードを変更せずに他のプロジェクトで再利用できます。