• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
Question by sean244 · Apr 18, 2018 at 07:08 PM · eventssingletondelegatesevent-listenereventlistener

How to unsubscribe from a delegate that is inside of a singleton?

In my GameManager, I have a delegate. In my Door script, I subscribe to this delegate. I've tried unsubscribing from it in both the OnDisable and OnDestroy methods in the Door script. In both cases, I get an error when I stop running the game in the editor:

 Some objects were not cleaned up when closing the scene. (Did you spawn new GameObjects from OnDestroy?)

Using Debug.Log, I found out that this is because the GameManager is getting destroyed before the Door script. Even if I do a null check inside either the OnDisable or OnDestroy of the Door script to see if the GameManager is null, I get the same error

 if (GameManager.Instance)
     {
         GameManager.Instance.OnAllEnemiesKilled -= OpenDoor;
     }

Somebody told me that I don't need to unsubscribe from it, as the delegate will automatically become null when the Door object is destroyed, but that's not true. During runtime, after the Door is destroyed, my update loop inside of the GameManager is still printing that the delegate has one subscriber: the Door.

Comment
Bunny83
Pikarie

People who like this

2 Show 3
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image JedBeryll · Apr 18, 2018 at 07:28 PM 0
Share

You could put it in a try-catch block to make it go away if it only happens in the editor. Won't bother you in a build.

avatar image Hellium JedBeryll · Apr 18, 2018 at 09:14 PM 0
Share

If you know the error will occur, don't hide it under a blanket. Fix the problem.

avatar image sean244 JedBeryll · Apr 18, 2018 at 09:35 PM 0
Share

Unfortunately, this try catch doesn't seem to work

 private void OnDisable()
 {
     try
     {
         GameManager.Instance.OnAllEnemiesKilled -= OpenDoor;
     }
     catch (Exception e)
     {
         Debug.LogError(e, this);
     }
 }

2 Replies

· Add your reply
  • Sort: 
avatar image
Best Answer

Answer by Bunny83 · Apr 18, 2018 at 10:29 PM

The problem is your singleton implementation. When you stop the game the singleton object will be destroyed as well. However since you access "Instance" in OnDestroy you will recreate the manager. There are several solutions to this problem. First of all this is mainly an issue in the editor. When OnDestroy is called due to stopping playmode the environment is currently resetting / reloading the previously serialized state. When you create objects at this stage they would interfer with the scene representation during edit time.


One solution would be to avoid recreating the singleton when it got destroyed. For this you could simply add a static bool to the singleton which you set to true in the OnDestroy method of the singleton. Inside your Instance getter you only create an instance when that static variable is false. Of course that would mean you can't rely on the Instance returning an object when used in OnDestory.


Another way is to bypass the overloaded "==" operator in your singleton implementation and do an actual reference equal check. Even when the singleton gets destroyed, the managed object is still alive but a null check would usually return true.

So instead of

 if (m_Instance == null)

you could simply do

 if ((object)m_Instance == null)

Note that this approach does not work if your singleton instance can actually be destroyed during runtime as that would mean it can never be recreated.

Comment
sean244

People who like this

1 Show 5 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image sean244 · Apr 19, 2018 at 12:37 AM 0
Share

The if ((object)m_Instance == null)solution worked perfectly. Thank you :) I call DontDestroyOnLoad(this.gameObject); in the Awake function of the singleton, so I don't anticipate any problems with your solution. Thank you so much! Should I still unsubscribe from the event like this

    If(GameManager.Instance)
        GameManager.Instance.OnAllEnemiesKilled -= OpenDoor;

or should I leave the if statement out of it? Also, I subscribe to the delegate in the Start function whereas some other people do it in the OnEnable function. Which one do you think I should use? Thanks again!

avatar image Bunny83 sean244 · Apr 19, 2018 at 01:41 AM 0
Share

You wouldn't need to check if Instance is null since the property will actually return an object. Even when a UnityEngine.Object derived object has been "destroyed" it's still there in the managed world. It just became a fake-null object. So this check:

 If(GameManager.Instance)

would fail on fake null objects and you would skip the unsubscribing. However in your case it doesn't really matter if you unsubscribe or not when you actually exit playmode ^^

avatar image sean244 Bunny83 · Apr 19, 2018 at 01:44 AM 0
Share

Great, one last thing, should I subscribe in the Start method or in the OnEnable method?

Show more comments
avatar image

Answer by Hellium · Apr 18, 2018 at 08:50 PM

Have you tried to simply set to null the event in the OnDestroy / OnDisable of your GameManager? https://stackoverflow.com/questions/91778/how-to-remove-all-event-handlers-from-an-event

Comment

People who like this

0 Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image sean244 · Apr 18, 2018 at 09:27 PM 0
Share

That doesn't seem to work, unless I stop trying to unsubscribe from it in my Door script.

avatar image Hellium sean244 · Apr 18, 2018 at 09:30 PM 0
Share

If you set to null the event in the GameManager, you don't need to unsubscribe in the other classes ;)

avatar image sean244 Hellium · Apr 18, 2018 at 09:32 PM 0
Share

But that means it won't unsubscribe during runtime, it will only unsubscribe after the game stops running. Don't I want it to unsubscribe during runtime, after the door is destroyed?

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

81 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Make prefab that generated more than once listener in Unity Events 0 Answers

Can you use UnityEvents to invoke methods with parameters from other classes? how?,UnityEvents with arguments resulting in a lot of errors. UnityAction? how? 1 Answer

Help to understand events and delegates (Game Manager) 2 Answers

Argument 1: cannot convert from 'method group' to 'UnityAction' 1 Answer

Problems with GameManagers 3 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges