Unity 5.1 Has broken the use of singleton patterns?

Hey guys, just updated to 5.1 and I’m getting errors such as

and

The latter of the two being a real deal-breaker for singletons. I’ve been using this particular class for over 5 years now and I’d really not like to have to remove it!

Does anyone have a work-around or tips? Maybe I’m just missing something simple?

For good measure, here’s my (now busted) singleton class. It’s a common one with a few tweaks I’ve added over the years…

using UnityEngine;

namespace com.pixelfat.unity.utility
{
  
    /// <summary>
    /// Be aware this will not prevent a non singleton constructor
    ///   such as `T myT = new T();`
    /// To prevent that, add `protected T () {}` to your singleton class.
    ///
    /// As a note, this is made as MonoBehaviour because we need Coroutines.
    /// </summary>
    public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
    {
        private static T _instance;
      
        private static object _lock = new object();

        protected Singleton () {}

        public static T Instance
        {
            get
            {
                if (applicationIsQuitting)
                {

                    if(_instance == null)
                        Debug.LogWarning("[Singleton] Instance '"+ typeof(T) +
                                         "' already destroyed on application quit." +
                                         " Won't create again - returning null.");

                    return _instance;

                }
              
                lock(_lock)
                {
                    if (_instance == null)
                    {
                        _instance = (T) FindObjectOfType(typeof(T));
                      
                        if ( FindObjectsOfType(typeof(T)).Length > 1 )
                        {
                            Debug.LogError("[Singleton] Something went really wrong " +
                                           " - there should never be more than 1 singleton!" +
                                           " Reopenning the scene might fix it.");
                            return _instance;
                        }
                      
                        if (_instance == null)
                        {
                            GameObject singleton = new GameObject();
                            _instance = singleton.AddComponent<T>();
                            singleton.name = "(singleton) "+ typeof(T).ToString();

                            Singleton<T> _s = _instance as Singleton<T>;
                            _s.Init();

                            DontDestroyOnLoad(singleton);
                          
                            Debug.Log("[Singleton] An instance of " + typeof(T) +
                                      " is needed in the scene, so '" + singleton +
                                      "' was created with DontDestroyOnLoad.");
                        } else {
                            Debug.Log("[Singleton] Using instance already created: " +
                                      _instance.gameObject.name);
                        }
                    }
                  
                    return _instance;
                }
            }
        }
      
        private static bool applicationIsQuitting = false;
        /// <summary>
        /// When Unity quits, it destroys objects in a random order.
        /// In principle, a Singleton is only destroyed when application quits.
        /// If any script calls Instance after it have been destroyed,
        ///   it will create a buggy ghost object that will stay on the Editor scene
        ///   even after stopping playing the Application. Really bad!
        /// So, this was made to be sure we're not creating that buggy ghost object.
        /// </summary>
        public void OnDestroy () {
            applicationIsQuitting = true;
        }

        protected virtual void Init() {;}

    }

}

Why are you locking your code ?

You should NEVER use Unity’s components in another thread.

BTW, you should use “FindObjectsOfType”, store the result, check if there are not more than one result and if not, take the first index. Doing this, you will not use “FindObject(s)OfType” twice.

You may have an Awake in your singleton where you just call Instance in order to initialize it. When you make sure that the other threads are not accessing it too early in the first frame, it should work as far as I can see.

I’ve removed the lock and also all references to FindObjectsOfType for test purposes, now it’s just simply:

  if (_instance == null) {
 
                        _instance = new GameObject("instance", typeof(T)).GetComponent<T>();

                        _instance.name = "(singleton) "+ typeof(T).ToString();

                        Singleton<T> _s = _instance as Singleton<T>;
                        _s.Init();

Unfortunately, the second line is still throwing the error. (Assigning the new instance to _instance).

The error is being thrown before any of my classes are used at C:/buildslave/unity/build/artifacts/generated/common/runtime/UnityEngineGameObjectBindings.gen.cs:424

It’s definitely related to a change in Unity 5.1, no idea which one though…

What happens in the other thread that is calling your singleton? Can’t you delay the creation of the thread?

Update: Turns out it was because of an assignment that was just damned hard to find:

private ChallengeEditorCursor.CURSOR_STATE mCursorControlState = ChallengeEditorCursor.Instance.state;

Weird that it only started happening since the 5.1 update, but happy to have found it and learned a bit! Thanks guys, beers are owed!!

1 Like