Unity GameObject의 OnDestroy의 호출은 보장되지않는다.

유니티 문서
https://docs.unity3d.com/kr/530/ScriptReference/MonoBehaviour.OnDestroy.html

 

 

#. OnDestroy()

유니티에서 Monobehaviour를 상속받는 객체가 파괴될 때 호출되는 함수이다.

파괴될 때의 동작이라는 점에서 객체를 생성한다거나 코루틴을 실행하면 오류를 발생시킬 여지가 많다는 것은 잘 알려져 있다.

 

하지만 옵저버 시스템으로 이벤트 방식을 사용하게 되면서 예전에는 숙지하지 못했던 부분이 보였다.

 

우선 평소에는 다음과 같은 코드를 주로 작성한다. 당연히 문제없이 잘 작동한다.

public class Parent : MonoBehaviour
{
    public void Awake()
    {
        // 이벤트 구독
    }

    public void OnDestroy()
    {
        // 이벤트 구독취소
    }
}

 

여기서 약간 심화적으로 들어가면

객체의 동작이 비대해지면서 컴포넌트 형태로 기능을 빼게 되면서 다음과 같은 코드를 작성하게 된다.

public class Parent : MonoBehaviour
{
    public MyComponent myComponent = new MyComponent();
    
    public void OnDestroy()
    {
        myComponent.Dispose();
    }
}

public class MyComponent : IDisposable
{
    public MyComponent()
    {
        // 이벤트 구독
    }

    public void Dispose()
    {
        // 이벤트 구독취소
    }
}

컴포넌트로 C# 객체를 사용하였기 때문에,

그럴듯한 진입점인 생성자에 구독을 넣고, OnDestory()에 구독취소를 호출하였다.

 

이 경우에도 자칫 문제가 없어 보이지만,

문제는 Parent 객체가 한 번도 SetActive 된 적이 없는 상태로 삭제되는 경우이다.

(예를 들어 상점 UI와 관련된 이벤트였고, 상점은 로비에서 로드되었으나 활성화되지 않은 상태로 스테이지에 진입했다)

 

이 경우 씬을 전환할 때 OnDestory는 호출되지 않아 Dispose()가 구독취소되지 않고,

이벤트는 구독자가 null인 상태로 씬이 전환된다.

(때문에 유령상태의 null 구독자가 남아버려서 있지도않은 객체에 이벤트가 호출되니 null오류가 팡팡터진다!)

 

 

유니티 매뉴얼을 보면 OnDestory의 중요한 특징을 언급하고 있다.

 

OnDestroy는 이전에 활성화되어있던, 게임 오브젝트상에서만 호출됩니다.

 

 

객체가 파괴될 때 무조건 특정 이름의 함수가 호출되는 방식이 아니라

객체가 처음 활성화될 때 구독되거나, 플래그를 세우는 형태인 것이다. 

 

유니티를 처음 시작했을 당시에는 절대 상관하지 않을 정도의 디테일 부분인데

나중에 숙련되고 나서는 매뉴얼을 보지 않게 되니 놓치는 부분인 듯하다.

 

 

댓글

Designed by JB FACTORY