I have a singleton script like this I apply to every middle guy that transfer dynamic data.
Like UI gather info during gameplay section.
public class SingletonEditorExample : MonoBehaviour
{
private static SingletonEditorExample _instance;
public static SingletonEditorExample Instance
{
get
{
#if UNITY_EDITOR
if (_instance != null) return _instance;
_instance = FindObjectOfType<SingletonEditorExample>();
Debug.Log("Refresh Editor. Finding Singleton Instance");
if (_instance == null)
{
_instance = new GameObject("SingletonEditorExample").AddComponent<SingletonEditorExample>();
Debug.LogWarning("Instance Object not created or missing. Created temporary object: " + _instance.GetType().Name, _instance);
}
#endif
return _instance;
}
set { _instance = value; }
}
private void Awake()
{
if (_instance == null)
_instance = this;
else
DestroyImmediate(this);
}
}
This one work fine except when exit play mode. The script sometime throw error creating new GameObject(Singleton) because some object not destroyed still call this Instance(already destroyed).
It didn’t see it a big problem but is there any better way to implement the Singleton? Because it still an error when quit game, so I am not entirely sure what could go wrong after exit game.
When I use a Singleton in Unity I provide a method or property which can be used to check if the instance actually exists. For anything that might be called after the Singleton is destroyed I then check that first, mostly when in OnDestroy().
// In the Singleton's MonoBehaviour
private static SingletonThing instance = null;
public static SingletonThing Instance {
get {
if (instance == null) CreateInstance();
return instance;
}
}
// Lets you see if it exists without accidentially instantiating it.
public static bool HasInstance {
get {
return instance != null;
}
}
// Some other MonoBehaviour
void OnDestroy() {
if (SingletonThing.HasInstance) {
// Do stuff that uses SingletonThing.Instance
}
}
Alternatively, I don’t have the Singleton instance accessor create the instance at all. I do that manually in the Editor, in Awake() I set the instance variable, and in OnDestroy() I unset it, with appropriate checks like so:
The catch with this approach is that now you need to null check everywhere you use the SingletonThing, rather than only checking against accidental recreation in the places where that might happen.
Note: Code here is to show the concept only, I haven’t tested it.
And the code above will create new Instance that already exist when in Editor Play mode refresh(import changed scripts in realtime). It is quite inconvenience that I have to replay the editor every time I changed 1 line of script.
And place OnDestroy() on every other MonoBehaviour script that use Singleton was not exactly the practice I was looking for. So thanks
Well, you don’t have to do that. The example OnDestroy() was only to show where/how I use the HasInstance variable in my own usage, to avoid the problem you originally asked about.
That is to say, I use it in cases where I’m making a call to a Singleton where it might have already been destroyed and I don’t want to accidentally recreate it. A classic example is with objects that register to listen for events on creation and unregister on destruction. If destruction is happening on a scene change or Editor mode change then I don’t want to accidentally re-create a Singleton that’s already destroyed, so I check HasInstance first. If you don’t do things from OnDestroy() then there’s no reason to add an OnDestroy().