Почему instance в синглтоне становится null?

133
26 сентября 2021, 10:20

Есть класс UIManager, написанный по принципу синглтона.

using System.Collections.Generic;
using UnityEngine;
using System;
public class UIManager : MonoBehaviour
{
    public static UIManager Instance;
    public List<GameObject> Windows = new List<GameObject>();
    void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject);
        }
        else if (Instance != this)
            Destroy(gameObject);
        InitUI();
    }
    private void InitUI()
    {
        //to do
    }

    void Start()
    {
        foreach (var window in Windows)
        {
            var windowComponent = window.GetComponent<Window>();
            if (windowComponent is LoginWindow)
                windowComponent.Open();
            else
                windowComponent.Close();
        }
    }
    public T GetWindow<T>() where T : Window
    {
        foreach (var window in Windows)
        {
            var windowComponent = window.GetComponent<Window>();
            if (windowComponent is T)
                return (T)windowComponent;
        }
        return null;
    }
}

Есть абстрактный класс Window, который реализуют все окна в сцене

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public abstract class Window : MonoBehaviour
{
    public bool IsOpen { get; private set; }
    public Window CurrentWindow { get; protected set; } = null;
    public delegate void OpenEventHandler(Window sender);
    public event OpenEventHandler OnOpen;
    void Awake()
    {
        UIManager.Instance.Windows.Add(this.gameObject);
    }
    public void Open()
    {
        IsOpen = true;
        if (OnOpen != null)
            OnOpen(this);
        SelfOpen();
    }
    protected abstract void SelfOpen();
    public void Close()
    {
        IsOpen = false;
        if (CurrentWindow != null)
            CurrentWindow.Close();
        SelfClose();
    }
    protected abstract void SelfClose();
    protected void ChangeCurrentWindow(Window sender)
    {
        if (CurrentWindow != null)
            CurrentWindow.Close();
        CurrentWindow = sender;
    }
}

В Window в методе Awake() окно регистрируется в UIManager-е путем добавления ссылки на окно в список. Но возникает странное поведение, когда я запускаю сцену из редактора, то часть окон регистрируется, а часть нет, потому что Instance в менеджере становится равным null. Отсюда вопрос, почему он становится null? Если сбилдить проект, то там все работает нормально, но это не объясняет сути.

Answer 1

Скорей всего все дело в том что у вас какие-то скрипты выполняются раньше, какие то позже. Поставьте класс UIManager в настройках Edit\ProjectSettings\ScriptExecutionOrders в начало списка, тогда и в редакторе должно нормально все отрабатывать.

Answer 2

Странный у вас синглтон. Почему экземпляр класса задается при вызове метода Awake?

Попробуйте использовать нормальный паттерн:

/// <summary>
/// Implements the singleton design pattern.
/// A class inheriting from this class can be instantiated as a single instance.
/// </summary>
/// <typeparam name="T">Class type of the singleton instance.</typeparam>
[DebuggerStepThrough]
public abstract class Singleton<T> : MonoBehavior where T : new()
{
    #region Fields
    /// <summary>
    /// Static instance. Needs to use lambda expression
    /// to construct an instance (since constructor is private).
    /// </summary>
    private static Lazy<T> _instance = new Lazy<T>(() => new T());
    #endregion
    #region Properties
    /// <summary>
    /// Gets the instance of this singleton.
    /// </summary>
    public static T Instance
    {
        get => _instance.Value;
        set
        {
            _instance = new Lazy<T>(() => value);
        }
    }
    #endregion
}

После этого:

public class UIManager : Singleton<UIManager>
{
    ... // Добавьте ваши методы здесь
}

Обращение к экземпляру осуществлять через

UIManager.Instance
READ ALSO
Zabbix запрос. Запрос в C#

Zabbix запрос. Запрос в C#

По регламенту ZABBIX: HEADER> - "ZBXD\x01" (5 байт) DATALEN> - размер данных (8 байт)число 1 отформатируется в 01/00/00/00/00/00/00/00

99
Изменение protected field вне сборки

Изменение protected field вне сборки

Можно ли изменить значение вне сборки?

146
Как изменить поле /Producer в pdf документе без сторонних библиотек

Как изменить поле /Producer в pdf документе без сторонних библиотек

Есть pdf документЯ использую следующий код, для того, чтобы его открыть и изменить значение /Producer

104