Какая разница между performSelectorOnMainThread и dispatch_async в главной очереди?
У меня возникли проблемы с изменением вида внутри потока. Я попытался добавить subview, но для отображения потребовалось около 6 секунд. Я, наконец, получил его работу, но я не знаю, как именно. Поэтому мне было интересно, почему это сработало и какая разница между следующими способами:
//this worked -added the view instantly
dispatch_async(dispatch_get_main_queue(), ^{
//some UI methods ej
[view addSubview: otherView];
}
//this took around 6 or more seconds to display
[viewController performSelectorOnMainThread:@selector(methodThatAddsSubview:) withObject:otherView
waitUntilDone:NO];
//Also didnt work: NSNotification methods - took also around 6 seconds to display
//the observer was in the viewController I wanted to modify
//paired to a method to add a subview.
[[NSNotificationCenter defaultCenter] postNotificationName:
@"notification-identifier" object:object];
Для справки это было вызвано внутри этого обработчика Completetion класса ACAccountStore.
accountStore requestAccessToAccountsWithType:accountType withCompletionHandler:^(BOOL granted, NSError *error) {
if(granted) {
//my methods were here
}
}
Изменить: Когда я говорю, что это не сработало, я намеревался, что потребовалось около 6 секунд, чтобы отобразить представление, которое я добавил.
Ответы
Ответ 1
По умолчанию -performSelectorOnMainThread:withObject:waitUntilDone:
только назначает селектор для запуска в режиме цикла запуска по умолчанию. Если цикл запуска находится в другом режиме (например, режим отслеживания), он не будет работать, пока цикл выполнения не вернется в режим по умолчанию. Вы можете обойти это с помощью варианта -performSelectorOnMainThread:withObject:waitUntilDone:modes:
(путем передачи всех режимов, в которые вы хотите его запустить).
С другой стороны, dispatch_async(dispatch_get_main_queue(), ^{ ... })
будет запускать блок, как только цикл основного запуска вернет поток управления обратно в цикл событий. Он не заботится о режимах. Поэтому, если вы не хотите заботиться о режимах, dispatch_async()
может быть лучшим способом.
Ответ 2
Вероятно, потому что performSelectorOnMainThread:withObject:waitUntilDone:
ставит в очередь сообщение с общими режимами цикла запуска. Согласно Apple Concurrency Руководство по программированию, основная очередь будет чередовать задачи с очередью с другими событиями из цикла запуска приложения. Таким образом, если в очереди событий есть другие события, очереди в очереди отправки могут быть запущены первыми, даже если они были отправлены позже.
Эта статья является превосходным объяснением performSelectorOnMainThread
vs. dispatch_async
, которое также отвечает на вышеупомянутый вопрос.
Ответ 3
Вы пробовали PerformSelectorOnMainThread
с помощью waitUntilDone=YES
Например:
Код:
[viewController performSelectorOnMainThread:@selector(methodThatAddsSubview:) withObject:otherView waitUntilDone:YES];
Я думаю, что это может решить вопрос о том, почему PerformSelectorOnMainThread
так долго реагирует.