Я пытаюсь предотвратить вход в сцену, если некоторые вещи с сервера не загружены, у меня есть флаг bool
done = false;
CCHttpRequest *pRequest;
// initialization ....
pRequest->setResponseCallback(this, httpresponse_selector(SceneController::on_response));
CCHttpClient::getInstance()->send(pRequest);
pRequest->release();
while(!done) {
std::chrono::milliseconds duration(1);
std::this_thread::sleep_for(duration);
}
в функции обратного вызова on_response
Я поставил
done = true;
что должно (но не работает) выйти из бесконечного цикла.
Проблема этого подхода заключается в том, что обратный вызов никогда не вызывается (точка останова на первой строке обратного вызова никогда не достигается). Когда я комментирую while loop
это называется обратным вызовом.
Кто-нибудь знает, в чем проблема и как предотвратить дальнейшее выполнение, пока я не получу данные с сервера?
Callstack, когда он работает на точке останова внутри callback
Обратный вызов — это НЕ другая нить, как вы думаете. Вы пытаетесь удержать текущее выполнение функции ‘пока обратный вызов не будет вызван’. Это не правильно. Вы должны вернуться из него и разрешить обратный вызов. Это должно сделать:
done = false;
CCHttpRequest *pRequest;
// initialization ....
pRequest->setResponseCallback(this, httpresponse_selector(SceneController::on_response));
CCHttpClient::getInstance()->send(pRequest);
pRequest->release();
if (!done)
{
return;
}
else
{
// Do here whatever you want to do after callback changes flag
}
Весь ваш код будет выполняться в потоке Cocos, CCHttpRequest имеет свой собственный поток для извлечения данных с сервера, а затем, когда все данные были извлечены, обратный вызов, который вы зарегистрировали ранее, также будет вызываться в потоке Cocos.
После регистрации обратного вызова поток Cocos продолжает выполняться на ваш while
, теперь обратный вызов не вызывается (данные не завершены) ваш while
будет работать вечно Когда данные завершены, необходимо выполнить обратный вызов в потоке Cocos, но вы видите while
продолжайте блокировать это.
В асинхронном мире (посмотреть здесь, и здесь, вы должны понимать async), вы не можете «предотвратить дальнейшее выполнение, пока не получите данные с сервера» по шаблону, который вы используете. Попытайтесь предотвратить это своими done
Переменная в местах, которые вы хотите, не будет выполнена.
Например:
done = false;
CCHttpRequest *pRequest;
// initialization ....
pRequest->setResponseCallback(this, httpresponse_selector(SceneController::on_response));
CCHttpClient::getInstance()->send(pRequest);
pRequest->release();
и затем в любом случае вы не хотите, чтобы пользователь взаимодействовал с вашим игровым интерфейсом, как в Touch:
void onTouchBegan(Event *pEvent, Touch *pTouch)
{
if (!done)
{
return false;
}
// code when `done == true`
}
void onTouchEnded(Event *pEvent, Touch *pTouch)
{
// Code here will not be executed if `onTouchBegan` return `false`
}
всякий раз, когда onTouchBegan
верните false, сенсорный код больше не будет выполняться, и пользователь не сможет взаимодействовать с игровым элементом.
Также, чтобы предотвратить нажатие кнопок в меню, отключите родительский контейнер меню: menu->setEnabled(false)
затем вернитесь к активному, когда загрузка завершена.