mystic-agit 개발 블로그

[Unity] EditorWindow 노출 상태에서 .cs 코드 수정 시 UI가 닫히는 이슈 본문

Unity

[Unity] EditorWindow 노출 상태에서 .cs 코드 수정 시 UI가 닫히는 이슈

mystic-agit 2025. 2. 4. 16:50

(1) 배경

  • Unity에서 여러 프로젝트에 사용할 수 있는 플러그인이나 SDK 등을 사용하다 보면
    적용하는 개발자가 편히 사용할 수 있는 설정 GUI를 만드는 경우가 있음
  • GUI 구성 시 Unity의 EditorWindow를 사용하는 경우 아래와 같은 형태로 설정 기능을 제공할 수 있음

 

(2) 문제 발생

  • 이슈 시나리오
    • 적용중인 개발자가 EditorWindow를 켜놓고 Unity C# 소스코드를 수정
    • 소스코드 수정 후 Unity 프로젝트 화면으로 포커스되면 변경된 소스코드를 컴파일 진행
    • 이때 열려있던 EditorWindow UI가 강제 종료되는 현상 발생

 

(3) 원인 분석

  • 에러 발생

  • 에러 내용 확인
    • 코드를 타고 들어가보면 EditorWindow를 다시 그리기 위해 OnGUI() 호출 및 진행 중
      OnGUI() 내부에서 UI를 그리기위해 사용되는 객체의 값이 없어서 참조할 수 없어 발생
      • 예를 들어, 지역변수 private static string labelName 이란 변수가 있었고
        EditorWindows 클래스 생성 시 labelName = “abc” 라는 값을 할당
      • 처음 EditorWindow 노출 시 라벨에 “abc” 값이 정상 노출되었으나
      • 소스코드 갱신으로 컴파일 진행 시 labelName 변수 값이 null 이라 exception 발생
      • UI 종료
public class MyEditorWindow : EditorWindow
{
	private static string labelName;
    
    public void init()
    {
    	labelName = "abc";
    }
    
    [MenuItem("MyGUI/MyEditorWindow")]
    public static void create()
    {
    	var editor = (MyEditorWindow)EditorWindow.GetWindow(typeof(MyEditorWindow), true, "MyEditorWindow");
        editor.init();
        editor.Show();
    }
    
    void OnGUI()
    {
    	EditorGUILayout.LabelField(labelName, ...);
        // ...
    }
}

 

 

(4) 소스코드 컴파일 시 생명주기

  • C# 코드를 수정하면 Unity는 컴파일을 진행하고 EditorWindow 상태를 갱신, 이 과정에서 생명주기 이벤트가 순차적으로 진행

 

(4-a) 컴파일 전

  • OnBeforeAssemblyReload()
    • [InitializeOnLoad] 속성이 붙은 클래스에서 실행 가능
    • Assembly가 다시 로드되기 전에 호출됨
    • 사용 예 : 현재 상태 저장, 파일 닫기 등
using UnityEditor;
using UnityEngine;

[InitializeOnLoad]
public class AssemblyReloadHandler
{
    static AssemblyReloadHandler()
    {
        AssemblyReloadEvents.beforeAssemblyReload += BeforeReload;
    }

    private static void BeforeReload()
    {
        Debug.Log("Assembly Reload 시작!");
    }
}

 

(4-b) 컴파일

  • .cs 파일이 변경되었는지 감지 후 컴파일
  • EditorWindow가 해제되거나 기존 상태가 사라질 수 있음

 

(4-c) 컴파일 완료 후

  • OnAfterAssemblyReload()
    • Assembly가 다시 로드된 직후 실행됨
    • 사용 예 : 데이터 복원, 다시 설정하기 등
using UnityEditor;
using UnityEngine;

[InitializeOnLoad]
public class AssemblyReloadHandler
{
    static AssemblyReloadHandler()
    {
        AssemblyReloadEvents.afterAssemblyReload += AfterReload;
    }

    private static void AfterReload()
    {
        Debug.Log("Assembly Reload 완료!");
    }
}

 

  • EditorWindow 다시 활성
    • EditorWindow 다시 생성
    • OnDisable() > OnDestroy() > OnEnable() > OnGUI() 순서로 실행
메서드 설명
OnDisable() 기존 EditorWindows가 비활성화될 때 호출
OnDestroy() 기존 EditorWindow가 완전히 삭제될 때 호출
OnEnable() 새 EditorWindow가 생성될 때 호출
Awake() OnEnable() 직후 한번 호출
OnGUI() UI를 다시 그리기 위해 호출

 

(4) 해소 방향

  • 앞서 사용한 labelName 변수에 사용되는 값을 어떤 형태로 사용하는가에 따라 해소 방향이 달라질 수 있지만
    일반적으로 OnGUI() 과정에서 사용되는 변수나 객체가 null인지 확인하고 그 값을 재할당해주는 방법이 필요
    • OnGUI() 과정에서 변수가 객체를 null 체크하여 하나하나 값을 불러오는 방법도 있지만
    • OnEnable() 메서드에서 OnGUI() 에서 사용되는 변수 및 객체를 일괄적으로 null 체크하여 미리 할당하면
      생명주기를 이해하고 있는 개발자간에 유지보수에 도움이 될 수 있음
private void OnEnable()
{
    if(labelName == null) 
    {
         // set labelName
         labelName = "abc";
    }
}

 

 

(5) 대응 결과

  • EditorWindow를 띄워놓은 상태에서 C# 소스코드가 변경되어 다시 컴파일 되어도 여전히 노출되어있음
  • 참고사항
    • 현재 EditorWindow에서 체크박스, 텍스트필드 등 어떤 UI에 해당하는 정보를 적용중인 개발자가 변경하였다면
      해당 UI의 변경값을 다른 클래스 static 변수가 저장하거나 로컬 데이터로 확보 후 OnEnalbeI()에서 get하여 사용한다면 UI를 다시 그리게 되어도 설정 상태를 손실하지 않을 수 있음

 

Comments