Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

singleton implementation

Discussion in 'Scripting' started by lacost, Jul 17, 2013.

  1. lacost

    lacost

    Joined:
    May 30, 2012
    Posts:
    1,740
    Hello guys!
    I just wondering how you implement singleton for MonoBehavior components

    Here is how I do it. I use this two methods depends of situation.

    The first:
    Code (csharp):
    1.  
    2. public class MyController : MonoBehaviour {
    3.  
    4.     private static MyController _insatnce;
    5.    
    6.     //--------------------------------------
    7.     // INITIALIZE
    8.     //--------------------------------------
    9.  
    10.     void Awake() {
    11.         _insatnce = this;
    12.     }
    13.    
    14.     //--------------------------------------
    15.     // GET / SET
    16.     //--------------------------------------
    17.  
    18.     public static MyController insatnce {
    19.         get {
    20.             return _insatnce;
    21.         }
    22.     }
    23. }
    24.  
    And the second one:

    Code (csharp):
    1.  
    2. public class MyController : MonoBehaviour {
    3.  
    4.     private static MyController _insatnce;
    5.    
    6.    
    7.     //--------------------------------------
    8.     // GET / SET
    9.     //--------------------------------------
    10.  
    11.     public static MyController insatnce {
    12.         get {
    13.             if(_insatnce == null) {
    14.                 _insatnce =  new GameObject("MyController").AddComponent<MyController>();
    15.             }
    16.             return _insatnce;
    17.         }
    18.     }
    19. }
    20.  

    And I always wanted to find solution, how to build base Siglethon class.
    I mean if I will deliver any component from this base Siglethon class the component will become Siglethon.
    Probably somebody know elegant solution how to do this.
     
    Last edited: Jul 17, 2013
  2. Patico

    Patico

    Joined:
    May 21, 2013
    Posts:
    886
    I know this: ;-)
    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public abstract class SingletoneBase<T> : MonoBehaviour
    5.     where T : class
    6. {
    7.     /// <summary>
    8.     /// SingletoneBase instance back field
    9.     /// </summary>
    10.     private static T instance = null;
    11.     /// <summary>
    12.     /// SingletoneBase instance
    13.     /// </summary>
    14.     public static T Instance
    15.     {
    16.         get
    17.         {
    18.             if (instance == null)
    19.             {
    20.                 instance = GameObject.FindObjectOfType(typeof(T)) as T;
    21.                 if (instance == null)
    22.                     Debug.LogError("SingletoneBase<T>: Could not found GameObject of type " + typeof(T).Name);
    23.             }
    24.             return instance;
    25.         }
    26.     }
    27. }
    28.  
    MyController singletone
    Code (csharp):
    1.  
    2. public class MyController : SingletoneBase<MyController >
    3. {
    4.     ///TODO:
    5. }
    6.  
     
    Last edited: Jul 17, 2013
  3. lacost

    lacost

    Joined:
    May 30, 2012
    Posts:
    1,740
    Patico, nice one, thx :)

    I will add it to my project!
     
  4. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,562
    Patico's solution will work. There are several different ways to truly implement the singleton pattern. One thing you have to be careful with is concurrency. Patico's implementation isn't really thread safe in that if you have MonoBehaviors being created in two separate threads, both could see the _instance variable as null and both could initialize it.

    In your example though, you're not really going to create a singleton. Every time an instance of the MonoBehavior is created it is going to reassign it to the _instance static variable.

    And actually, in either case your behavior isn't actually a singleton. What's happening is you're taking the first instantiation of your MonoBehavior and you're storing it in the _instance variable. Every other time, the behavior is still getting instantiated, so you're still getting a new instance every time, but if you're using the _instance variable, you're going to be working on the same actual instance of the behavior.

    MonoBehaviors aren't really designed to be singletons either... so let's say you have stuff that happens in Update and FixedUpdate. Update and FixedUpdate will still be called for every gameobject you have this behavior attached to. Not only that, you will need to do something like this:

    Code (csharp):
    1.  
    2. void Update()
    3. {
    4.     _instance.Update();
    5. }
    6.  
    Of course you could use a Factory to implement it... something like this:

    Code (csharp):
    1.  
    2.    public static class BehaviorFactory
    3.    {
    4.          private static Dictionary<type, MonoBehavior> Behaviors = new List<type>();
    5.  
    6.          public static T GetBehavior<T>() where T : MonoBehavior, new()
    7.          {
    8.                  T result = null;
    9.                   if(Behaviors.ContainsKey(typeof(T))
    10.                   {
    11.                          return Behaviors[typeof(T)] as T;
    12.                   }
    13.                   else
    14.                   {
    15.                         var result = new T();
    16.                         Behaviors.Add(typeof(T), result);
    17.                         return result;
    18.                   }
    19.  
    20.           }
    21.  
    22.     }
    23.  
    24.  
    Then you'd have to add your behaviors through code using your factory to assign the instance. You'd still have the issue of the lifecycle methods being fired more than once. You'd also have the issue of your behavior getting destroyed if your gameObject gets destroyed.
     
    Last edited: Jul 17, 2013
    StormChaser13 likes this.
  5. lacost

    lacost

    Joined:
    May 30, 2012
    Posts:
    1,740
    My example are the simplest implementation of this pattern, and sure it not 100% safe. But this is enough in 90% cases, at least for me :)

    The first example can be used only for components with are on stage after initialization (you do not create them in runtime)
    And the second will work fine if you call it only thru instance getter.

    Patico suggested really good implementation. Yes it's not thread safe. Let's remember that Unity API is also not thread safe. Point is that if soumebody will need thread safe Patico's solution can be extended by adding double lock. But I guess that there is not mutch people who use Threads instead coroutines.
     
  6. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,503
    I'd be very curious to know how you're creating a MonoBehaviour in a different thread. :)
     
  7. cdevl

    cdevl

    Joined:
    Apr 10, 2013
    Posts:
    180
    If you really need to channel the lifecycle methods through a singleton (have exactly one instance executing Start, Update, Awake, etc...) then use "delegate" and "singleton" patterns together.

    1. Create a templated Monobehaviour that owns a singleton that is not a monobehaviour
    2. that singleton should mimic monobehaviour interface (but NOT be a monobehaviour because u don't want to instantiate monobehaviours yourself). Create your own interface for that possibly.
    3. have your monobehaviour delegate all lifecycle calls to a singleton. It can even pass additional parameters if your singleton needs to know for example the transform of the caller.
     
  8. Patico

    Patico

    Joined:
    May 21, 2013
    Posts:
    886
    Yes, it is simple non tread-safe implementation. If you want a tread-safe - all you need is to add a double checking lock pattern wiki.

    But, I've not used locking in Unity yet, if this is well supported by engine, then next code should works well and tread-safe:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public abstract class SingletoneBase<T> : BaseMonoBehaviour
    5.     where T : class
    6. {
    7.     /// <summary>
    8.     /// SingletoneBase instance back field
    9.     /// </summary>
    10.     private static T instance = null;
    11.     private static readonly Object syncRoot = new Object();
    12.     /// <summary>
    13.     /// SingletoneBase instance
    14.     /// </summary>
    15.     public static T Instance
    16.     {
    17.         get
    18.         {
    19.             if (instance == null)
    20.             {
    21.                lock(syncRoot)
    22.                {
    23.                   if (instance == null)
    24.                   {
    25.                       instance = GameObject.FindObjectOfType(typeof(T)) as T;
    26.                       if (instance == null)
    27.                           Debug.LogError("SingletoneBase<T>: Could not found GameObject of type " + typeof(T).Name);
    28.                   }
    29.                }
    30.             }
    31.             return instance;
    32.         }
    33.     }
    34. }
    35.  
     
  9. VRARDAJ

    VRARDAJ

    Joined:
    Jul 25, 2017
    Posts:
    17
    I know this thread is super old, but I've revisited it many times over the years because I've never been quite satisfied. I want to set up a singleton with as little code as possible, and I also want that setup to not interfere with existing inheritance for the class in question. Anyone who has set up a few singletons with generics and inheritance knows that it's a pain in the butt to try to inherit anything into your singleton while its in this configuration. So I thought I'd try setting up a singleton via property declaration instead. It occurred to me that If I keep the property name short, then it's only two extra keystrokes to ref the instance, which feels like a wonderful trade-off for me when it gets the singleton setup out of the inheritance tree. Here's a first pass:

    Code (CSharp):
    1.  
    2. using System;
    3. using System.Collections;
    4. using System.Collections.Generic;
    5. using UnityEngine;
    6.  
    7. /// <summary>
    8. /// A singleton designed to set up via property declaration rather than class declaration
    9. /// so as to avoid interference with any existing inheritance structure
    10. ///
    11. /// /// Setup:
    12. /// public class YOURCLASS : MonoBehaviour
    13. /// {
    14. ///     public static Singleton<YOURCLASS> _ = new Singleton<YOURCLASS>();
    15. /// }
    16. ///
    17. /// /// Usage:
    18. /// YOURCLASS._.Instance.DoStuff();
    19. ///
    20. /// </summary>
    21. /// <typeparam name="T">the type you want to declare as a singleton</typeparam>
    22. public class Singleton<T> where T : MonoBehaviour
    23. {
    24.     public T Instance
    25.     {
    26.         get
    27.         {
    28.             if (m_Instance == null)
    29.                 m_Instance = (T)GameObject.FindObjectOfType(typeof(T));
    30.             return m_Instance;
    31.         }
    32.     }
    33.     private static T m_Instance;
    34. }
    35.  
     
    Last edited: Jul 24, 2020
  10. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,503
    That's not really a Singleton though because you can have multiple instances of YOURCLASS attached to many GameObjects. That's just a MonoBehaviour with a static reference to some other MonoBehaviour (which may or may not be itself)
     
    Suddoha likes this.
  11. VRARDAJ

    VRARDAJ

    Joined:
    Jul 25, 2017
    Posts:
    17
    I'm aware, but I personally prefer them not to be real singletons. I do not want accidentally duped singletons deleted automatically, so I usually delete that part from singleton implementations. Instead, I prefer error handling on duplication, which is still technically not a singleton because the error doesn't stop a multiple-instance situation... it just flags your attention to it. But that's what I prefer. I just haven't put that in here yet bc this is a first pass. The point is more that you can implement a singleton any way you want via class OR via property, and it all works the same way. Only difference is a couple extra keystrokes to reference the instance. RE: That's just a MonoBehaviour with a static reference to some other MonoBehaviour... no. It's a MonoBehaviour with a static reference to itself. A singleton of sorts. Just like feeding a child class type ref into its parent class as a generic is a monobehaviour inheriting a static reference to itself. The only difference is syntax.
     
    Last edited: Jul 25, 2020
  12. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    917
    Is this to save a few lines of code for the dozen or so times you need a singleton?

    Code (csharp):
    1. public class Foo : MonoBehavior
    2. {
    3.   public static Foo Instance { get; private set; }
    4.  
    5.   public void Awake()
    6.   {
    7.     Instance = this;
    8.   }
    9. }
     
    Last edited: Jul 25, 2020
  13. VRARDAJ

    VRARDAJ

    Joined:
    Jul 25, 2017
    Posts:
    17
    Yup, exactly. This was the first thing I wrote and realized it's the core of what I wanted, but then realized I still want to template-ize other common aspects of a singleton like error handling, locking, and duplication deletion. Mine started as the same as what you've got here, but then I abstracted the property to open up the ability to add all that extra stuff.
     
  14. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    917
    I'm having a hard time imagining what kind of locking and error handling you would need here. And I don't really know what duplication deletion means. I certainly don't see any of that in your code.

    Were you going to add it later? Are you leaving it as an exercise to the reader? If the latter, I'm afraid I would need more context to understand how to do that.
     
  15. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,503
    You're not guaranteeing that.
    Code (csharp):
    1.  
    2. var a = new GameObject();
    3. var b = new GameObject();
    4. var first = a.AddComponent<YourClass>();
    5. var second = b.AddComponent<YourClass>();
    6.  
    second's static reference is actually to first, not itself.

    I also think it's generally better for the static reference to instantiate itself fully the first time it's called. Your implementation relies on someone putting the component in a scene somewhere ahead of time so there's a chance Instance will be null.
     
  16. VRARDAJ

    VRARDAJ

    Joined:
    Jul 25, 2017
    Posts:
    17
    Again, I'm aware of that. What I posted was a first pass. The fact that I didn't add duplication deletion yet does not mean it's impossible to do so. Like I said, you can easily add it the same way as in the generic derived class implementation. There is no difference between declaring the singleton as a property vs. a derived class, except syntax. I don't personally care about duplication deletion, but if you really need me to prove they're equivalent, I can code you an example.
     
  17. VRARDAJ

    VRARDAJ

    Joined:
    Jul 25, 2017
    Posts:
    17
    I didn't intend to add any more to my post. It was just an idea that I thought would be interesting for people who like to build their own singletons. Locking and duplication deletion are covered in previous posts in this thread. The go-to singleton implementation in the Unify wiki does both. You can copy the contents of one of those solutions and paste it into the body of the code I posted. The only thing unique about my way is that it lets you declare your singletons as properties instead of declaring them as generic derived classes. Everything else can be the same.

    It's not common to put error handling in a singleton bc widely shared forum code with Debug.Log statements can be annoying, but all it means is when a duplicate is found, throw an error to the console instead of deleting the duplicate.
     
  18. VRARDAJ

    VRARDAJ

    Joined:
    Jul 25, 2017
    Posts:
    17
    My mistake, the wiki only does locking, which is not useful in Unity anyway for a MonoBehaviour since it will always init on the main thread unless you job it, and if you have to job singletons, you're probably making too many of them.

    I could swear the wiki used to handle duplication deletion too, but apparently not anymore. Here's the link: http://wiki.unity3d.com/index.php/Singleton

    You can implement duplication deletion by writing an else block after the null check...
    Code (CSharp):
    1. if (m_Instance == null)
    2. {...}
    3. else Destroy(this);
     
  19. VRARDAJ

    VRARDAJ

    Joined:
    Jul 25, 2017
    Posts:
    17
    RE: "no chance the instance will be null," I despise null-check instantiation in singletons. If someone wrote a race condition, I want the console to throw an error at them immediately so they know to fix it. Singletons instantiating themselves on the spot is an instant havoc recipe in my book, but to each their own. Like with all the other things, you're welcome to add null-check instantiation, whether via generic derived class singletons or via property singletons.
     
  20. VRARDAJ

    VRARDAJ

    Joined:
    Jul 25, 2017
    Posts:
    17
    There's a lot of back-and-forth about what constitutes a singleton in this thread. In the spirit of hoping to avoid reiterating that I don't think any of us need most of the features that are popular in Unity singletons, the following are 100% completely IMO what a singleton needs and does not need, and why this works perfectly for me:

    Do Need:
    * Fast declaration syntax for any number of classes that may or may not have their own inheritance pattern already
    * Fast accessor syntax
    * Duplicate error handling just in case (very rarely needed)

    Don't Need:
    * Locking
    * Duplication Deletion
    * Null-check instantiation
    * Multi-instance discovery handling of any kind, really

    In general, my singletons are singletons because I decided there's only one, not because the code guarantees there's only one, and that's usually plenty good enough for me, and for the teams I've worked with. The name Singleton implies it. Has anyone here run into a situation where you needed the code to guarantee it? If the team sees the name singleton, they know it's a thing not to be duplicated. If you're afraid someone will goof this, throw an error on duplicate discovery. If a singleton that doesn't have multi-instance handling doesn't count as a singleton according to the community at large, we can agree to disagree.

    My singletons are either pre-installed in an init scene, or a core Init script instantiates them prior to any scene load. They should not be created using AddComponent, Instantiate on an intra-scene prefab, etc. Singletons are top-level classes (God-mode classes) to be used very sparingly. Scenes, objects, and scene-level behaviours are not allowed to create singletons in my code. Singletons have authority over scenes and intra-scene prefabs, not the other way around. When I use them with teams, we agree upon singleton usage guidelines. They're super dangerous if different team members use them differently, but if everyone's on the same page, duplicates usually aren't a thing.

    Telling your fellow team members not to dupe singletons is sort of like telling them not to call a private method from outside its class. 1) Obvious. 2) A thing that obvious should turn your console red if you overlook it. But the popular way with Unity singletons is to paper over that mistake and then build extra handlers to clean up the aftermath too. Time spent handling multiple instances is not just wasted... it causes more problems than it solves. For example, ScriptA calls a singleton accessor. Singleton constructor shows the singleton not found... a) give ScriptA's author a null ref? Or B) create a new singleton on the spot and pretend ScriptA's author messed up nothing... Problem is, the singleton you wanted is about to be instantiated next frame. ScriptA's author could yield for it, but they didn't even get an indication that they just created a race condition. If your singleton implementation creates a copy to paper over the race condition, next frame you have two singletons, and now it's a good thing you built that duplicate handling. Rather than using singletons in an error-prone way and doing extensive work to paper over the mistakes the team doesn't know they're making, just let them have the errors that reveal their mistakes in the first place, and they'll quickly learn how to use singletons correctly.
     
    Last edited: Aug 15, 2020
  21. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    8,967
    Can I play? I hate dragging manager-y crap into the scene because that's just a disaster and hassle waiting to happen when you're working from team. "Oh now you have to always start from scene Launcher.unity" Who has time for that?! The game should start from whatever scene you're working in.

    Here's what I use:

    Simple Unity3D Singleton (no predefined data):

    https://pastebin.com/SuvBWCpJ

    Unity3D Singleton with Prefab used for predefined data:

    https://pastebin.com/cv1vtS6G

    These are pure-code solutions, do not put anything into any scene, just access it via .Instance.

    Also, I treat AddComponent as if it were private, always, and do this for everything else:

    Factory Pattern in lieu of AddComponent (for timing and dependency correctness):

    https://pastebin.com/euGb7t3k
     
    StormChaser13 and VRARDAJ like this.
  22. VRARDAJ

    VRARDAJ

    Joined:
    Jul 25, 2017
    Posts:
    17
    I dig it. I'm totally onboard with eliminating Load scenes, although I do like to configure my singletons in inspector. It's why we bother making them MonoBehaviours, IMO. Could be done w/ scriptable objects instead, but any time I start considering SOs, I usually realize it's time to level up to a full-on database and/or DI framework, etc. 80% of the time, the Mono version comes first bc it's lightning fast to slap in place, and then every once in a while an upgrade is necessary.
     
  23. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,752

    Well, it's better not to call it a singleton in the first place if it does not satisfy the techincal contract and the implications of it.

    That's a lose agreement. The singleton pattern in software engineering is something that you implement on a technical level.

    If we're just talking about agreements rather than the actual pattern, anything that is only instantiated once - consciously or not - conforms to that in that giving context.

    So code a console program, only instantiate a single object... weil, here you go... a singleton in that very context. Would you now say object is a singleton? Probably not.


    Yes, always. Because that's what the name implies and that's what a developer expects.

    Even when you're aware how to set things up, when you communicate that something is a singleton, one expects certain technical implications. It sort of must be foolproof.

    In other words, if you don't ensure it's technically a singleton, don't label it as such. That should be the primary "recipe in your book".

    You may call this nitpicking, however, despite all the freedoms and variants of implementing the pattern, you cannot just completely ignore half of its widely-accepted definition.
     
    Last edited: Aug 15, 2020
    KelsoMRK and Yoreki like this.
  24. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    8,967
    Me too... that would be my second link above, the one that takes the prefab. It would be trivial to reconfigure that to instead load a ScriptableObject instance if you prefer, just one more object to go along with this script. That would let you use the same MonoBehavior "driver" but configure it with different ScriptableObject instances, such as one for "paid mode" and one for "free trial mode" builds, or really anything.
     
  25. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,503
    I'm confused. You don't want to null check your singleton but you also don't want it to load itself when you attempt to access it. Pretty hard to have it both ways honestly.

    Except fast declaration and access aren't part of what makes a singelton a singleton and duplication deletion is pretty much the only way you can guarantee that in the context of a MonoBehavior living in a scene. As @Suddoha put very well - when you say "singleton" there are expectations associated with this, which is why we pointed out that what you did isn't a singleton. If it works for you doing stuff by yourself then go for it - we're just pointing out inconsistencies in your terminology and the resulting gaps in your implementation.
     
    Suddoha likes this.
unityunity