Последний, когда задействован метод Update
, который также должен ожидать выполнения при использовании async
, и await
может быть недостаточно в любом случае.
Обычно всегда есть одна большая альтернатива использованию async
для сообщений Unity: система событий, например,
public static class Localization
{
public static event Action OnLocalizationReady;
public static async void Initialize()
{
await LoadMetaData();
OnLocalizationReady?.Invoke();
}
...
}
И дождитесь этого события в любом классе, используя его, например,
public class LanguageMenu : MonoBehaviour
{
private bool locaIsReady;
private void Awake()
{
Localization.OnLocalizationReady -= OnLocalizationReady;
Localization.OnLocalizationReady += OnLocalizationReady;
Localization.Initialize();
}
private void OnDestroy ()
{
Localization.OnLocalizationReady -= OnLocalizationReady;
}
// This now replaces whatever you wanted to do in Start originally
private void OnLocalizationReady ()
{
locaIsReady = true;
Debug.Log(Localization.Available.Count);
}
private void Update()
{
// Block execution until locaIsReady
if(!locaIsReady) return;
...
}
}
Или для минимально лучшей производительности вы также можете установить enabled = false
в Awake
и установить значение true в OnLocalizationReady
, тогда вы сможете избавиться от флага locaIsReady
.
Нет async
и await
необходимо.
Если бы вы переместили Localization.Initialize();
вместо Start
, вы бы дали другим классам возможность также добавить некоторые обратные вызовы до Localization.OnLocalizationReady
в Awake
;)
И вы можете расширить это несколькими способами! Вы могли бы, например, вместе с инициированием события напрямую также передается ссылка на Availables
, чтобы слушатели могли напрямую использовать его, например,
public static class Localization
{
public static event Action<List<string>> OnLocalizationReady;
...
}
, а затем в LanguageMenu
изменить подпись OnLocalizationReady
на
public class LanguageMenu : MonoBehaviour
{
...
// This now replaces whatever you wanted to do in Start originally
private void OnLocalizationReady(List<string> available)
{
locaIsReady = true;
Debug.Log(available.Count);
}
}
Если в любом случае LanguageMenu
будет единственным прослушивателем, вы можете даже передать обратный вызов непосредственно в качестве параметра Initialize
, например
public static class Localization
{
public static async void Initialize(Action<List<string>> onSuccess)
{
await LoadMetaData();
onSuccess?.Invoke();
}
...
}
и затем используйте его как
private void Awake()
{
Localization.Initialize(OnLocalizationReady);
}
private void OnLocalizationReady(List<string>> available)
{
locaIsReady = true;
Debug.Log(available.Count);
}
или как лямбда-выражение
private void Awake()
{
Localization.Initialize(available =>
{
locaIsReady = true;
Debug.Log(available .Count);
}
}
Обновление
Что касается вашего вопроса о последующей инициализации: Да, есть и простое исправление
public static class Localization
{
public static event Action OnLocalizationReady;
public static bool isInitialized;
public static async void Initialize()
{
await LoadMetaData();
isInitialized = true;
OnLocalizationReady?.Invoke();
}
...
}
Тогда в других классах вы можете сделать это условно, либо использовать обратные вызовы, либо сразу же инициализировать:
private void Awake()
{
if(Localization.isInitialized)
{
OnLocaInitialized();
}
else
{
Localization.OnInitialized -= OnLocaInitialized;
Localization.OnInitialized += OnLocaInitialized;
}
}
private void OnDestroy ()
{
Localization.OnInitialized -= OnLocaInitialized;
}
private void OnLocaInitialized()
{
var available = Localization.Available;
...
}
private void Update()
{
if(!Localization.isInitialized) return;
...
}