Запуск обработчика завершения NSURLSession в основной теме
Я использую NSURLSession, чтобы получить значения для заполнения TableView. Я обновляю TableView в обработчике завершения, но использование [[NSThread currentThread] isMainThread]
показало мне, что обработчик завершения не работает в основном потоке. Поскольку я должен только обновлять пользовательский интерфейс из основного потока, я знаю, что это неверно. Есть ли способ вызвать действие в основном потоке из обработчика завершения? Или использует 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];
Ответы
Ответ 1
Да, просто отправьте свой основной материал с помощью 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];
Ответ 2
@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];
Таким образом вы создаете сеанс, который вызывает блок завершения и любые методы делегата в основном потоке. Вы можете найти это более эстетически приятным, но вы теряете преимущество в том, что выполняете "тяжелую работу" в фоновом режиме.
Ответ 3
Вы можете попробовать следующее:
[self.userTableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:NO];
Ответ 4
Вот лучший способ обновить интерфейс от блоков и обработчика завершения, а также, когда вы не поймете, какой поток работает с вашим кодом.
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
});
Ответ 5
отправить уведомление о завершении, которое будет наблюдаться контроллером табличного представления, который затем выполнит команду reloadData;
это имеет то преимущество, что если вы позже переместите этот код загрузки в отдельный класс, например, объект модели, то никаких изменений не требуется, а также код может быть повторно использован в других проектах без внесения изменений
Ответ 6
Swift 3.1
DispatchQueue.main.async {
if (Thread.isMainThread) {
tableView.reloadData()
}
}