Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Possible to bypass OnDisable() on application quit?

Discussion in 'Scripting' started by Tetrad, Sep 1, 2009.

Thread Status:
Not open for further replies.
  1. Tetrad

    Tetrad

    Joined:
    Jul 22, 2009
    Posts:
    45
    I have a simple script that spawns some particles when an object gets destroyed (like a projectile).

    Code (csharp):
    1.  
    2. public class DestructionParticlesScript : MonoBehaviour
    3. {
    4.     public GameObject[] particlePrefabs;
    5.    
    6.     void OnDisable()
    7.     {
    8.         foreach( GameObject particlePrefab in particlePrefabs )
    9.         {
    10.             // I assume these particles auto-destroy
    11.             Instantiate( particlePrefab, transform.position, transform.rotation );         
    12.         }
    13.     }
    14. }
    15.  
    Now, if you stop the game while the particles are active, because they're not parented to anything (I presume), they would remain in the scene.

    That is, until I added this script to the particle prefabs themselves:

    Code (csharp):
    1.  
    2. public class DestroyOnQuit : MonoBehaviour
    3. {
    4.     void OnApplicationQuit()
    5.     {
    6.         Debug.Log( "Destroying " + name );
    7.         Destroy( gameObject );
    8.     }
    9. }
    10.  
    Now that works for if the particles are in in the process of playing and you stop the in-editor game.

    The problem that I'm running into is that if you quit running the in-editor game while the projectile is in mid-air, the OnDisable gets called for the projectile (spawning the particles), but OnApplicationQuit for the spawned prefabs doesn't get called, leaving the instantiated clones of the particle prefabs in the scene and the warning "!objects.empty ()". Is there any way to see if the OnDisable is being caused by the application quitting, or some other workaround so that I don't have rogue spawned particles cluttering the scene?

    I'm using Unity iPhone 1.5 but it happened on earlier versions as well and I presume the non-iPhone versions of Unity.
     
  2. Cawas

    Cawas

    Joined:
    Jan 14, 2010
    Posts:
    121
    I just stumbled on a similar issue, but with very different effects...

    Using a previous more simplistic version of this Singleton, I had a script with `OnDisable` to call my `Manager.Instance` and, some times, it does it after the Instance have been destroyed. That would generate a very weird bug. And so I wanted to "bypass OnDisable on application quit" as well.

    Since this is 4 years old you probably solved your question already... Or gave up programming. But, in case anyone stumble here first, like I did, there's the solution I've used (the Singleton script re-edited).

    For you case, the solution would be analogously similar. Keep in mind `OnDisable` is called after `OnApplicationQuit`. So add a `OnApplicationQuit` to `DestructionParticleScript` to set a dirty flag the application is quitting. Something along the lines:

    Code (csharp):
    1.  
    2. public class DestructionParticlesScript : MonoBehaviour
    3. {
    4.     public GameObject[] particlePrefabs;
    5.     private bool isApplicationQuitting = false;
    6.    
    7.     void OnDisable()
    8.     {
    9.         if (isApplicationQuitting) return;
    10.  
    11.         foreach( GameObject particlePrefab in particlePrefabs )
    12.         {
    13.             // I assume these particles auto-destroy
    14.             Instantiate( particlePrefab, transform.position, transform.rotation );          
    15.         }
    16.     }
    17.  
    18.     void OnApplicationQuit () {
    19.         isApplicationQuitting = true;
    20.     }
    21. }
    22.  
     
    Last edited: Oct 21, 2013
  3. dbanfield

    dbanfield

    Joined:
    Apr 20, 2013
    Posts:
    8
    It may have been four years old but this saved me a lot of head scratching!
    Thanks Cawas!
     
    Cawas likes this.
  4. Cawas

    Cawas

    Joined:
    Jan 14, 2010
    Posts:
    121
    Cool! You're very welcomed! :)
     
  5. KyleStaves

    KyleStaves

    Joined:
    Nov 4, 2009
    Posts:
    821
    I'm really surprised we still don't have an Application.IsQuitting bool so we don't need to manually cache this.
     
  6. imtrobin

    imtrobin

    Joined:
    Nov 30, 2009
    Posts:
    1,548
    yes, I'm surprised too.
     
  7. Pawl

    Pawl

    Joined:
    Jun 23, 2013
    Posts:
    113
    +1, I just ran into this exact issue with OnDestroy() and the Singleton found on the Unity wiki. Application.IsQuitting would make a lot of sense here.

    Is it guaranteed that OnApplicationQuit() will get called before OnDestroy() for all MonoBehaviors? If so, you could implement your own MyApplication class and cache the boolean there, rather than once per MonoBehavior.

    EDIT: According to this picture http://docs.unity3d.com/Manual/ExecutionOrder.html it looks like OnDestroy() gets called before OnApplicationQuit(), so this does need to be cached once per MonoBehavior (sigh).

    EDIT2: If you feel this would be a useful feature, please vote for it here: http://feedback.unity3d.com/suggestions/applicationisquitting-flag-to-d
     
    Last edited: Jul 23, 2014
    ModLunar and Cawas like this.
  8. crandellbr

    crandellbr

    Joined:
    Apr 3, 2013
    Posts:
    137
    I use my own Destroy() methods when practical, and I only just encountered the issue of OnDisable() being called while quitting now. Sadly, I doubt it will make a difference, but I voted anyway.

    The Execution Order flowchart is invaluable, but it appears...wrong? OnApplicationQuit() is clearly called before OnDisable(), verified with log statements and as described in the Unify link Cawas posted. In fact, the order is OnApplicationQuit() > OnDisable() > OnDestroy().
     
    imDanOush, Mycroft and Cawas like this.
  9. Mycroft

    Mycroft

    Joined:
    Aug 29, 2012
    Posts:
    160
    The Diagram must have been updated at some point because it now follows the order you suggest that it followed.
     
  10. Baumkuchen

    Baumkuchen

    Joined:
    Feb 14, 2016
    Posts:
    8
    Does anyone know if there is news?
     
  11. shottogan

    shottogan

    Joined:
    Feb 25, 2015
    Posts:
    3
  12. Remiel

    Remiel

    Joined:
    Oct 17, 2012
    Posts:
    105
    But this doesn't solve the issue of having to manually remember whether the app is quitting. This just adds the ability for us to put our code elsewhere instead of putting it in OnApplicationQuitting method. This callback is only useful if that code is located in an object that isn't a MonoBehavior. I would have far preferred a boolean instead of an event.

    As it stands now, I still have to make a useless method in my MonoBehaviours that only remembers whether the app is quitting so that I can safely unsubscribe from events in OnDestroy. :( Imagine how often I have to write this useless check, the alternative of which is relatively tedious.

    Unity... how hard is it to just implement a bool? It should only take two lines of code. One line for the definition of a property with a private setter, another for setting it to true before calling OnApplicationQuit methods... XD It would literally take less than a minute for any of Unity engineers to add this.

    Where do I vote for this since feedback has been shut down?
     
  13. henningsteinbock

    henningsteinbock

    Joined:
    Jun 2, 2021
    Posts:
    3
    What I found to be the cleanest workaround for this is to create a static class that subscribes to Application.quitting.
    But it would be very nice to have Application.isQuitting bool and I am a bit surprised that there is no such thing in the Unity API

    Code (CSharp):
    1.    
    2. using UnityEngine;
    3. #if UNITY_EDITOR
    4. using UnityEditor;
    5. #endif
    6.  
    7.  public static class QuitUtil
    8.     {
    9.         #region Static
    10.  
    11.         public static bool isQuitting;
    12.  
    13. #if UNITY_EDITOR
    14.         [InitializeOnEnterPlayMode]
    15.         static void EnterPlayMode(EnterPlayModeOptions options)
    16.         {
    17.             isQuitting = false;
    18.         }
    19. #endif
    20.  
    21.         [RuntimeInitializeOnLoadMethod]
    22.         static void RunOnStart()
    23.         {
    24.             isQuitting = false;
    25.             Application.quitting += Quit;
    26.         }
    27.  
    28.         static void Quit()
    29.         {
    30.             isQuitting = true;
    31.         }
    32.  
    33.         #endregion
    34.     }
     
  14. nathantokyo

    nathantokyo

    Joined:
    Aug 24, 2019
    Posts:
    1
    I was having a similar issue instantiating objects in OnDisable.

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

    What worked for me was to check if the scene was still loaded in OnDisable. This returned false both when quitting the app/editor and when unloading the scene.

    Code (CSharp):
    1.  
    2. void OnDisable()
    3. {
    4.         if(!this.gameObject.scene.isLoaded) return;
    5.        // Instantiate objects here
    6. }
    7.  
    Not sure this fully answers the original question but hopefully this helps someone.
     
    mcbombad, R2-RT, Trost_ and 3 others like this.
  15. twobob

    twobob

    Joined:
    Jun 28, 2014
    Posts:
    2,058

    I was just gonna write this
     
  16. Howey-Do-It

    Howey-Do-It

    Joined:
    Apr 19, 2013
    Posts:
    5
    @nathantokyo Thank you. This solved my issue perfectly.
     
    nathantokyo likes this.
Thread Status:
Not open for further replies.