Comments 13
Ну так уже много раз сказано и написано статей(даже на хабре), что синглтон нужно использовать очень осмотрительно, а лучше вообще не использовать. Сначала он выглядит просто и красиво, а чуть поже начинаются приседания. Что ваша статья добавляет ко всему сказаному?
+2
SinglEton, Карл. SinglE. Исправь, везде сингел.
+2
Не верю, что ничего подобного по синглтонам на Хабре не было. Даже если не здесь, то по интернетам подобной инфы размазано в изобилии. Любимая цацка начинающих юнитистов же!
FYI, на будущее, большая часть вот этой вот простынки:
Успешно заменяется на:
FYI, на будущее, большая часть вот этой вот простынки:
//Find T
T[] managers = GameObject.FindObjectsOfType<T>();
if (managers != null)
{
if (managers.Length == 1)
{
instance = managers[0];
DontDestroyOnLoad(instance);
return instance;
}
else
{
if (managers.Length > 1)
{
Debug.LogError($"Have more that one {typeof(T).Name} in scene. " + "But this is Singleton! Check project.");
for (int i = 0; i < managers.Length; ++i)
{
T manager = managers[i];
Destroy(manager.gameObject);
}
}
}
}
Успешно заменяется на:
FindObjectsOfType<T>().SingleOrDefault()
0
Вот этого не понял.
В одном случае мы проверяем, что на сцене нет объектов, которые создают ложные синглтоны (например при переходе между сценами оставили какой-то менеджер). И устраняем эти ложные объекты. Например при работе со фоновым звуком, в каждой сцене не надо иметь менеджер звука — нужно только его вызывать. И еще интересный момент — успешная замена в итоге вызовет исключение, если будет найдено более 1 объекта. То есть мы еще и поимеем обработку исключений. Адекватно ли это? FYI, абсолютно нет.
Касательно размазано — да так и есть, поэтому я предоставил ссылки, где предоставлен весь этот код. Я просто собрал его вместе и пояснил в чем его удобство. На гениальность не претендую)
В одном случае мы проверяем, что на сцене нет объектов, которые создают ложные синглтоны (например при переходе между сценами оставили какой-то менеджер). И устраняем эти ложные объекты. Например при работе со фоновым звуком, в каждой сцене не надо иметь менеджер звука — нужно только его вызывать. И еще интересный момент — успешная замена в итоге вызовет исключение, если будет найдено более 1 объекта. То есть мы еще и поимеем обработку исключений. Адекватно ли это? FYI, абсолютно нет.
Касательно размазано — да так и есть, поэтому я предоставил ссылки, где предоставлен весь этот код. Я просто собрал его вместе и пояснил в чем его удобство. На гениальность не претендую)
-1
Убивать невесть откуда взявшиеся дополнительные инстансы в рантайме, по-моему, весьма сомнительная идея — логичнее кинуть исключение и заставить автора фиксить логику, порождающую эти самые лишние инстансы, не?
+1
Так смысл синглтона в том, что он 1 будет на весь проект. Мы и так кинем сообщение об ошибке, но приложение останется работоспособным и не упадет. И убивать дополнительные инстансы является верным делом, так как они просто будут сидеть в памяти и все. А за счет DontDestroyOnLoad объект не будет почищен уборщиком памяти и просто будет висеть. У меня все приложении должны работать 24/7 без присмотра пользователя, если я оставлю exception, то при вызове какого-нибудь захудалого менеджера раз в 2-3 часа будет вызывать падение приложения. Или писать логику на обработчик ошибок (каждый раз разную). Такие доводы.
0
Мой комментарий выше был о том, чтобы в первую очередь не создавать лишние сущности — принцип, выполнение которого в данном конкретном случае можно обеспечить с помощью исключений. Вы же не будете индексировать массив с аргументом -1, правильно? Потому что среда выполнения выбросит исключение, а не молчаливо с лицом okay.jpg перетерпит. Вот тут то же самое. И это не что-то неконтролируемое, как, например, кривой JSON, пришедший от сервера, тут всё в Ваших руках. И Вам же будет лучше, не мне.
И да, DontDestroyOnLoad() не имеет отношение к сборщику мусора, если, конечно, Вы его имели в виду.
И да, DontDestroyOnLoad() не имеет отношение к сборщику мусора, если, конечно, Вы его имели в виду.
0
Смешно сказать, но очень часто индексирую (часто делают в обработке изображений для правильной обработки краев).
Логика в исключении есть — но давайте тогда подумаем, что мы за этим тянем? Дополнительная обработка исключений — кто-то должен отловить и обработать эту ошибку (а кто?). В итоге мы придем к тому же коду, только оформленному иначе.
Касательно DontDestroyOnLoad() -> он тащит за собой следующий вызов
Если лезть дальше, то просто помечается объект, не удалятся (KeepAlive()). И если мы накидаем несколько на сцену объектов одного класса, то когда будут уничтожены эти объекты? При выходе из приложения.
Как я это проверил — наследовал вышеуказанный синглтон и просто добавил в него счетчик созданных объектов (в конструктор и деструктор(финализатор)).
Вообще логика мне ваша понятна, но в данном случае я предпочитаю сделать так, чтобы точно держать в памяти 1 объект.
Логика в исключении есть — но давайте тогда подумаем, что мы за этим тянем? Дополнительная обработка исключений — кто-то должен отловить и обработать эту ошибку (а кто?). В итоге мы придем к тому же коду, только оформленному иначе.
Касательно DontDestroyOnLoad() -> он тащит за собой следующий вызов
/// /// Do not destroy the target Object when loading a new Scene.
///
/// An Object not destroyed on Scene change.
[MethodImpl(MethodImplOptions.InternalCall)]
[FreeFunction(«GetSceneManager().DontDestroyOnLoad»)]
public static extern void DontDestroyOnLoad(Object target);
Если лезть дальше, то просто помечается объект, не удалятся (KeepAlive()). И если мы накидаем несколько на сцену объектов одного класса, то когда будут уничтожены эти объекты? При выходе из приложения.
Как я это проверил — наследовал вышеуказанный синглтон и просто добавил в него счетчик созданных объектов (в конструктор и деструктор(финализатор)).
Вообще логика мне ваша понятна, но в данном случае я предпочитаю сделать так, чтобы точно держать в памяти 1 объект.
-1
Добавьте в заголовок про то, что это Singleton именно для Unity, пожалуйста.
Кстати ваша реализация не потокобезопасна.
Как минимум вот тут:
Если другой поток вызовет геттер после инициализации поля instance и до завершения работы метода Initialization, он получит недоинициализированный объект.
Ну и присоединяюсь к комментариям выше. Singleton редко когда на самом деле нужен и стоит его избегать. Хотя бывают исключения конечно.
Кстати ваша реализация не потокобезопасна.
Как минимум вот тут:
instance = go.GetComponent<T>();
instance.Initialization();
DontDestroyOnLoad(instance.gameObject);
return instance;
Если другой поток вызовет геттер после инициализации поля instance и до завершения работы метода Initialization, он получит недоинициализированный объект.
Ну и присоединяюсь к комментариям выше. Singleton редко когда на самом деле нужен и стоит его избегать. Хотя бывают исключения конечно.
0
Да, можно добавить блокировку (как советуют в указанных ресурсах), но это бессмысленно. Однако в Unity все сложно с потоками (половина функционала unity не может быть вызвана не из основного потока), поэтому если и запускать потоки дополнительной обработки — то в Start(). К тому времени все Awake отработают.
А мой класс вывалится с ошибкой даже с блокировкой — по той причине что вызов GetComponent() не может быть совершен не из главного потока. Поэтому ни о какой потокобезопасности и не может быть и речи. Один из вариантов — разделение по времени (то что выше описал).
А мой класс вывалится с ошибкой даже с блокировкой — по той причине что вызов GetComponent() не может быть совершен не из главного потока. Поэтому ни о какой потокобезопасности и не может быть и речи. Один из вариантов — разделение по времени (то что выше описал).
0
Sign up to leave a comment.
Singleton c учетом подводных камней