Search Unity

[Documentation] UnityEvent.RemoveAllListeners() only removes non persistent listeners

Discussion in 'Documentation' started by Nanity, Jul 18, 2015.

  1. Nanity

    Nanity

    Joined:
    Jul 6, 2012
    Posts:
    148
    EricJ13 and jannis99 like this.
  2. liortal

    liortal

    Joined:
    Oct 17, 2012
    Posts:
    3,562
    What do you mean by "non persistent listeners" ?
     
  3. Nanity

    Nanity

    Joined:
    Jul 6, 2012
    Posts:
    148
    UnityEvent contains a list of delegates that are called upon an event (e.g. OnClick() in the Button UI component). If you add new delegates via inspector they are "persistent" and can't be removed by script. On the other hand, if you call UnityEvent.AddListener(UnityAction) by script, it will add a "non persistent" delegate, that will not show up in the inspector.

    All public functions of UnityEvent only allow to remove "non persistent" listeners/delegates that were added by script. Those who were added via inspector only can be removed via the inspector. UnityEvent.RemoveAllListeners() implies to be able to remove "persistent" listeners although this is not true (tested!).
     
  4. Julien-Lynge

    Julien-Lynge

    Joined:
    Nov 5, 2010
    Posts:
    142
    Thanks Nanity!

    The whole persistent vs non-persistent listeners thing doesn't appear to be documented, so that was a helpful explanation.

    With that info, I poked through the UnityEngine source and come up with a solution for adding inspector (persistent) events via script. You just have to use reflection to get at the private method AddPersistentListener, which expects a delegate reference (and optional CallState).

    This is a problem I've found with the event system in general - not only is the documentation less than stellar, but it doesn't appear to have been set up with the intention of being heavily modifiable by the user. It's actually a rather nice system, and I hope they continue to expand it when they (someday) update the Input class, but hopefully in the meantime the community can continue to put together its own documentation and
     
  5. Nanity

    Nanity

    Joined:
    Jul 6, 2012
    Posts:
    148
    It's a nice piece of code yes. If they would rip out Unity Editor Drawers as seperate dll, they would have to rewrite a bunch of code because they call a lot of internal functions that are not available to us.

    Reflection works, but if you want to make deep changes you have so much clutter.

    Improvements might to be taken up into the Documentation, not sure what's the best communication channel though. This forum? Bug reports? Mail to the support? PM to Unity Employees?
     
  6. ChrisSch

    ChrisSch

    Joined:
    Feb 15, 2013
    Posts:
    763
    Thank you! I've been confused for a couple days why isn't adding/removing listeners working, been through countless google searches, until I found your post which explains what a persistent listener is, and that you can't manipulate one, and that non persistent listeners don't show up in inspector. Once I removed the persistent listeners, and added them through code, everything started working.

    Wish I knew how to add/remove persistent listeners though.
     
    miladekramnia likes this.
  7. duck

    duck

    Unity Technologies

    Joined:
    Oct 21, 2008
    Posts:
    358
    Hi Nanity, thanks for your post and your detailed follow-up. This is really useful and I'll make sure the manual gets updated!
     
    EricJ13, AmazinJacks and ChrisSch like this.
  8. Petethegoat

    Petethegoat

    Joined:
    Jun 12, 2013
    Posts:
    39
    Is there a method to count the number of non-persistent listeners?
    Nothing in the documentation that I can see- there's GetPersistentEventCount, but as the name suggests, it only returns the number of persistent listeners.
     
    CinnoMan likes this.
  9. amanpu

    amanpu

    Joined:
    Feb 12, 2015
    Posts:
    8
    It is worth noting that you can also remove persistent listeners from onClick event or any other event as following:
    1. gameObject.GetComponent<Button>().onClick = new Button.ButtonClickedEvent();
     
  10. duck

    duck

    Unity Technologies

    Joined:
    Oct 21, 2008
    Posts:
    358
    I've updated the docs, the info you've provided about persistent vs non persistent listeners will be in the next online update :) thanks!
     
  11. duck

    duck

    Unity Technologies

    Joined:
    Oct 21, 2008
    Posts:
    358
    The updated info is now online :)
     
    Nanity likes this.
  12. Floofloof

    Floofloof

    Joined:
    Nov 21, 2016
    Posts:
    41
    Any update on if we will be able to get info on the non persistent listeners? Seems we can still only see the persistent ones. I would like to know how many non persistent listener are on an event.
     
  13. rus89

    rus89

    Joined:
    Apr 22, 2015
    Posts:
    9
    If somebody need example how to remove persistent listener from code in editor, I found solution :)

    Code (CSharp):
    1.  
    2.         //Button on which you want to remove persistent listeners
    3.         Button inAppBackButton = inAppMenuGameObject.transform.GetChild(1).GetComponent<Button>();
    4.  
    5.         //Define what Method you want to call, and add it later as persistent listener
    6.         UnityEngine.Events.UnityAction action = gameControllerMenu.menus.settings.GetComponent<SettingsMenu>().ClickSoundPlay;
    7.         //or
    8.         UnityEngine.Events.UnityAction action1 = new UnityEngine.Events.UnityAction(gameControllerMenu.menus.settings.GetComponent<SettingsMenu>().ClickSoundPlay);
    9.  
    10.         //Define method with one argument
    11.         UnityEngine.Events.UnityAction<GameObject> actionWithGO = gameControllerMenu.menuManagerScript.ShowMenu;
    12.         //or
    13.         UnityEngine.Events.UnityAction<GameObject> actionWithGO1 = new UnityEngine.Events.UnityAction<GameObject>(gameControllerMenu.menuManagerScript.ShowMenu);
    14.  
    15.         //Remove all previous persistent listeners
    16.         UnityEditor.Events.UnityEventTools.RemovePersistentListener(inAppBackButton.onClick, 1);
    17.         UnityEditor.Events.UnityEventTools.RemovePersistentListener(inAppBackButton.onClick, 0);
    18.  
    19.         //Add new void persisten listener
    20.         UnityEditor.Events.UnityEventTools.AddVoidPersistentListener(inAppBackButton.onClick, action);
    21.  
    22.         //Add new persistent listener with GameObject as argument
    23.         UnityEditor.Events.UnityEventTools.AddObjectPersistentListener<GameObject>(inAppBackButton.onClick, actionWithGO, gameControllerMenu.menus.videoForCoinsMenu);
    24.  
    Hope someone will find it useful. Cheers.
     
  14. Keyserjaya99

    Keyserjaya99

    Joined:
    Nov 17, 2016
    Posts:
    10
    But it's works only on editor, sad... :' (
    Is there any way to make it works on runtime(build version)?
     
    vozcn and dmlightup like this.
  15. dmlightup

    dmlightup

    Joined:
    Jun 7, 2017
    Posts:
    15
    I would also be interested in hearing about workarounds for doing this in runtime. Thanks for the useful explanation @Nanity
     
  16. liuyi475

    liuyi475

    Joined:
    Apr 12, 2018
    Posts:
    1
    atalantus likes this.
  17. Israr_Rashid3

    Israr_Rashid3

    Joined:
    Oct 10, 2020
    Posts:
    3

    Hopefully, I found the solution for this problem, the solution is that we can change the UnityEventCallState to off. Let me show you an example:

    I add these methods through the inspector,
    upload_2022-5-28_20-42-2.png

    Now, I want to disable their execution using script, So I wrote these lines of code to change Unity Event Call State.
    upload_2022-5-28_20-43-30.png

    Now in play mode,
    upload_2022-5-28_20-46-6.png

    Conclusion: If we cannot remove the persistent listeners from the script then we can turn off the Unity event call state using the script. So in this way, we can get rid of persistent listeners during gameplay. I hope my solution satisfies your need.