원문: MonoBehaviour.OnApplicationQuit(), MonoBehaviour.OnDisable(), MonoBehaviour.OnDestroy()
참고용 예제 저장소: Unity Practice (Sungkuk Park)
최종 업데이트: 2018년 12월 30일

개요 (Overview)

본문은 Update 해제(decommissioning) 이벤트 함수 3형제인 OnApplicationQuit, OnDisable, OnDestroy를 소개하는 글이다. 각 함수에 해당하는 유니티 공식 문서를 참고했으며 예제 프로젝트를 빌드하면서 새로이 확인한 사항들도 본문에 추가했다. OnDisable의 경우는 최근 필자가 유니티 클라이언트 면접 당시 기출되었던 질문이므로 면접을 앞두고 있다면 한번 읽어봐도 좋을 것이다.

MonoBehaviour.OnApplicationQuit()

어플리케이션(application)이 종료되기 직전 모든 게임 내 객체들에게 전송된다.

에디터 상에서는 Play Mode를 종료할 때 호출된다.

참고 1: iOS 어플리케이션은 일반적으로 종료되는 대신 정지된다(suspended). 따라서, iOS 빌드의 경우 게임이 정지되는 대신 종료되게 만드려면 Player Settings의 “Exit on Suspend” 체크 박스를 활성화시켜야 한다. 그러지 않으면 이 경우 OnApplicationQuit 호출을 받을 수 없다. 만약 “Exit on Suspend”가 비활성화되어 있다면 OnApplicationPause가 대신 호출된다.

참고 2: 윈도우 스토어 앱이나 윈도우 폰 8.1의 경우 OnApplicationQuit 이벤트가 존재하지 않는다. 따라서 대신 focusStatus가 false와 같아질 때 OnApplicationFocus 이벤트 사용을 고려하라.

참고 3: WebGL의 경우 OnApplicationQuit을 구현할 수 없다. 이는 브라우저(browser)의 경우 탭(tabs)이 닫히는 방식이기 때문에 그렇다.

using UnityEngine;
 
 public class OnApplicationQuitExample : MonoBehaviour
 {
     private void OnApplicationQuit()
     {
         // Time.time은 현재 프레임이 시작되는 순간의 시간으로서 (읽기 전용),
         // 해당 시간은 게임이 시작된 이후 경과한 시간을 초로 나타낸 것이다.
         Debug.Log("어플리케이션이 " + Time.time + " 초 뒤에 종료되었습니다");
     }
 }

예제 출력 결과: “어플리케이션이 1.980064 초 뒤에 종료되었습니다”

MonoBehaviour.OnDisable()

OnDisable은 해당 Behaviour가 비활성화 상태가 되면 호출된다.

OnDisable은 객체가 파괴될 때에도 호출되며, 이 때문에 해당 구간에서 자원 해제(cleanup) 코드를 사용할 수도 있다. 컴파일이 끝난 직후 스크립트를 다시 불러올 때에도 OnDisable이 호출되며, 스크립트가 로드된 이후 뒤이어 OnEnable이 호출된다.

참고: OnDisable 함수는 Start와 달리 코루틴으로 사용할 수 없다.

using System.Collections;
using UnityEngine;

public class OnDisableExampleClass : MonoBehaviour {

    private void OnEnable() {
        Debug.Log("OnEnable");
    }

    private IEnumerator Start() {
        Debug.Log("Start");

        yield return new WaitForSeconds(2.5f);

        Destroy(gameObject);
    }

    private void OnDisable() {
        Debug.Log("OnDisable");
    }

    private void OnDestroy() {
        Debug.Log("OnDestroy");
    }
}

따라서 위의 OnDisableExampleClass가 유니티 상에서 활성화되었다고 가정할 때, 콘솔에 출력될 각 함수들의 호출 순서 내지 문자열은 다음과 같다:

OnEnable
Start
OnDisable
OnDestroy

MonoBehaviour.OnDestroy()

부착된 Behaviour가 파괴되는 경우 OnDestroy 메시지를 받게 된다.

OnDestroy는 씬(Scene)이나 게임이 종료될 때 발생한다. 데이터 상에서 Play Mode를 중단시키는 경우에는 해당 어플리케이션을 종료시키게 된다. 이 경우에도 OnDestroy가 호출된다. 또한, 현재 씬이 닫히고 다음 씬이 로드된 경우에도 OnDestroy가 호출된다. 스탠드얼론(standalone) 어플리케이션의 경우는 씬이 종료될 때 OnDestroy가 호출된다. 하나의 씬의 종료는 일반적으로 새로운 씬이 로드된 경우를 말한다.

참고 1: OnDestroy의 경우, 해당 게임 객체의 상태가 활성화(active) 상태였던 경우에만 OnDestroy가 호출된다.

아래 예제 코드를 보면 OnDestroy의 동작 방식을 이해할 수 있다. OnDestroyExample1 스크립트가 실행되면 버튼이 하나 활성화된다. 이 버튼을 통해 OnDestroy를 호출한 뒤 OnDestroyExample2 스크립트의 실행으로 넘어간다. OnDestroyExample2 스크립트가 활성화되고 나면, 어플리케이션을 종료하는 방식으로 두 번째 OnDestroy를 호출할 수 있다. 만약 OnDestroyExample1 스크립트가 어플리케이션을 종료하는 식으로 중단되더라도 역시 OnDestroy가 호출되게 된다.

using UnityEngine;
using UnityEngine.SceneManagement;

public class OnDestroyExample1 : MonoBehaviour
{
    private void Start()
    {
        Debug.Log("Start1");
    }

    private void OnGUI()
    {
        if (GUI.Button(new Rect(10, 10, 250, 60), "Scene 2로 이동"))
        {
            Debug.Log("Exit1WithButton");
            SceneManager.LoadScene("OnDestroyExample2");
        }
    }

    // Start() 이벤트 함수가 호출되기 전에 메시지를 생성한다
    private void OnEnable()
    {
        Debug.Log("OnEnable1");
    }

    // 게임이 종료되거나 다른 씬으로 이동할 때 메시지를 생성한다
    private void OnDestroy()
    {
        Debug.Log("OnDestroy1");
    }
}
using UnityEngine;

public class OnDestroyExample2 : MonoBehaviour
{
    private void Start()
    {
        Debug.Log("Start2");
    }

    private void OnEnable()
    {
        Debug.Log("OnEnable2");
    }

    // 게임이 종료되거나 다른 씬으로 이동할 때 메시지를 생성한다
    private void OnDestroy()
    {
        Debug.Log("OnDestroy2");
    }
}

따라서 위의 OnDestroyExample1 스크립트가 존재하는 씬을 시작으로 버튼을 눌러 OnDestroyExample2 스크립트가 존재하는 씬으로 이동한 후 어플리케이션을 종료한다고 가정할 때, 콘솔에 출력될 각 함수들의 호출 순서 내지 문자열은 다음과 같다:

OnEnable1
Start1
Exit1WithButton
OnDestroy1
OnEnable2
Start2
OnDestroy2
<끝>