Подтвердить что ты не робот

Запуск обработчика завершения 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];
4b9b3361

Ответ 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()
        }
}