Serialization, MonoBehaviour Constructor and Unity 5.4 (번역)

직렬화, MonoBehaviour 생성자 그리고 유니티 5.4

(Serialization, MonoBehaviour Constructor and Unity 5.4 번역)

– 원문 링크 –

 

Unity 5.4 버젼부터, 생성자 또는 필드 초기화 과정 및 Deserialization(loading, 로딩) 과정에서 Unity API가 호출되는 경우에 표시되는 오류 메시지를 추가했습니다.

이 오류 메시지의 목적은 Unity API의 사용 요구사항을 명확히 하고 잘못 사용하는 경우에 발생할 수 있는 부작용을 방지하기 위함입니다.

 

Unity API 대부분은 메인 쓰레드(main thread) 상에서만 호출되어야 합니다. 즉, MonoBehaviour의 Start/Update/등에서만 호출되어야 합니다.

유사하게, Debug.Log 또는 Mathf와 같이, Unity API의 일부만 스크립트 생성자/필드 초기화 과정에서 호출될 수 있습니다. Unity는 클래스의 인스턴스를 생성할 때 , Deserialization(load, 로드)과정 중에 생성자를 Invoke 하는데, Deserialization 과정은 메인 쓰레드가 아닌 다른 쓰레드에서 실행됩니다.

이 요구사항은 Unity 5.4 이전 버전에서는 엄격하게 적용되지는 않기 때문에, 크래쉬, 경쟁 조건(race conditions) 및 진단과 문제를 재구현하기 힘든 그런 문제를 발생시킬 수 있습니다.

Unity 5.4에서 이 새로운 오류 메시지는 대부분의 경우 , managed exception을 발생시키지 않고 스크립트의 실행 흐름도 방해하지 않습니다. 이전 버전에서 Unity 5.4로 프로젝트를 업그레이드 하는 과정에서 발생할 수 있는 문제를 줄이기 위해서 이런 접근 방법을 사용했습니다. 이 오류 메시지는 후에 릴리즈될 Unity 버전에서 managed exception이 발생하도록 계획하고 있습니다. 하지만 Unity 5.4로 프로젝트를 업그레이드할 때 위에 언급한 사항들은 수정하는 것을 권장합니다.

새로 추가된 오류 메시지는 메뉴얼의 Script Serialization 페이지에서 “Script Serialization Erros” 섹션에 문서화 되어 있습니다.

새로 추가된 Serialization 오류 메시지가 발생하는 시나리오 및 해결방법에 대해서 살펴보겠습니다.

 

생성자/필드 초기화 과정에서 Unity API 호출하기

Unity가 MonoBehaviour/ScriptableObject를 상속받은 클래스의 인스턴스를 생성할 때, managed object를 생성하기 위해서 기본 생성자를 호출합니다. 이 과정은 아직 메인 루프에 도달하지 못한 상태이며, 씬(scene)이 완전히 로드되지 않은 상태입니다. 필드 초기화 과정은 managed object의 기본 생성자가 호출되는 시점에 진행됩니다. 생성자에서 Unity API를 호출하는 것은, 대부분의 Unity API에서 안전하지 않다고 판단합니다.

예제:

public class FieldAPICallBehaviour : MonoBehaviour
{
   public GameObject foo = GameObject.Find("foo");
}

serialization error

public class ConstructorAPICallBehaviour : MonoBehaviour
{
   public ConstructorAPICallBehaviour()
   {
       GameObject.Find("foo");
   }
}

serialization error

위의 예제와 같은 경우에 “Find is not allowed to be called from a MonoBehaviour constructor (or instance field initializer), call in in Awake or Start instead…” 오류를 발생시킵니다.
이를 해결하는 방법은 Unity API를 MonoBehaviour의 Start함수에서 호출하는 것입니다.

 

 

Deserialization(로딩) 과정에서 Unity API를 호출하는 경우

Unity가 씬을 로드할 때, 저장된 씬으로부터 managed object들을 재-생성하고 생성된 오브젝트에 저장된 값을 적용합니다 (deserialization). Managed object를 생성하기 위해서는 해당 오브젝트들의 기본 생성자가 호출되어야 합니다. 만약 어떤 필드(field)가 저장된 오브젝트(serialized)를 참조하고 있고 이 오브젝트의 기본 생성자에서 Unity API를 호출하는 경우 씬을 로딩할 때 오류가 발생합니다. 위에서 설명한 오류와 같이, 아직 메인 루프에 도달하지 못했고 씬이 완전히 로드되지 않은 상태입니다. 따라서 이 경우 대부분의 Uniay API에서 안전하지 않다고 판단합니다.

예제:

public class SerializationAPICallBehaviour : MonoBehaviour
{
   [System.Serializable]
   public class CallAPI
   {
       public CallAPI()
       {
           GameObject.Find("foo");
       }
   }

   CallAPI callAPI;
}

deserialization error

이 경우, “Find is not allowed to be called during serialization, call it from Awake or Start instead.” 오류가 발생합니다. 이 문제를 해결하기 위해서는 저장된 오브젝트의 생성자에서 Unity API가 호출되지 않도록, 코드의 리펙토링이 필요합니다. 오브젝트에서 Unity API를 호출해야 하는 경우, Unity API가 메인 쓰레드에서 호출되도록, 반드시 Start, Awake, Update와 같은 MonoBehaviour 콜백함수에서 호출해야합니다.

RonnieJ

프리랜서 IT강사로 활동하고 있습니다. 게임 개발, 웹 개발, 1인 기업, 독서, 책쓰기에 관심이 많습니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 항목은 *(으)로 표시합니다