Quick Flow
OnEnable은 컴포넌트가 enabled이고 GameObject가 hierarchy에서 active일 때마다 호출됩니다. OnDisable은 그 상태가 깨질 때 호출됩니다. 한 번만 필요한 초기화는 Awake/Start, 활성 상태 동안만 유효해야 하는 구독·등록은 OnEnable/OnDisable에 둡니다.
private void OnEnable()
{
GameEvents.EnemyDied += HandleEnemyDied;
}
private void OnDisable()
{
GameEvents.EnemyDied -= HandleEnemyDied;
}| 목적 | 시작 지점 | 해제 지점 | 확인할 실패 |
|---|---|---|---|
| 컴포넌트 캐시·불변 초기화 | Awake | 필요 없음 | 재활성화 때 중복 초기화 |
| 씬 참조가 준비된 뒤 1회 설정 | Start | 필요 없음 | 비활성 시작 시 Start가 늦어짐 |
| 이벤트·UnityEvent 구독 | OnEnable | OnDisable | 풀 재사용 때 listener가 중복됨 |
| 활성 중인 코루틴 | OnEnable 또는 명시적 요청 | OnDisable | Behaviour만 꺼도 코루틴이 남음 |
| Input Action Map | 그 Map의 소유자 | 같은 소유자 | 공유 Map을 꺼서 다른 소비자 입력까지 막음 |
수명 경계
반복 호출을 전제로 작성하기
처음 활성화된 스크립트는 보통 Awake → OnEnable → Start 순서로 진행하고, 이후에는 활성/비활성 전환마다 OnEnable ↔ OnDisable이 반복됩니다. Start는 첫 활성화 뒤 최초 Update 전에 한 번만 호출됩니다. 씬에서 처음부터 비활성인 오브젝트는 활성화될 때까지 Start가 호출되지 않을 수 있습니다.
OnDisable은 GameObject 비활성화, Behaviour enabled 해제, 파괴 직전, Editor에서의 script reload 같은 경로에서 호출될 수 있습니다. 따라서 외부 이벤트 해제는 여러 번 불러도 안전해야 합니다. C# event의 -=는 아직 구독하지 않았어도 안전하지만, 커스텀 등록 API는 idempotent한지 확인합니다.
이벤트와 코루틴
private Coroutine _blinkHandle;
private void OnEnable()
{
PlayerHealth.Damaged += Refresh;
_blinkHandle = StartCoroutine(BlinkRoutine());
}
private void OnDisable()
{
PlayerHealth.Damaged -= Refresh;
if (_blinkHandle == null) return;
StopCoroutine(_blinkHandle);
_blinkHandle = null;
}SetActive(false)는 GameObject의 코루틴을 중단하지만, Behaviour 체크박스만 끈 경우에는 코루틴이 계속될 수 있습니다. 어느 수명에 묶을지 코드로 드러내야 합니다. 이벤트도 전역 이벤트라서 "항상 구독"해야 하는 경우가 아니라면 활성 수명에 맞춰 해제합니다.
Input Action Map의 소유자
InputActionMap.Enable()/Disable()는 해당 map을 사용하는 모든 action에 영향을 줍니다. UI와 게임플레이가 하나의 shared map을 참조한다면 한 컴포넌트의 OnDisable이 다른 컴포넌트 입력까지 꺼 버릴 수 있습니다. Map을 만드는 PlayerInput 또는 입력 상태 관리자처럼 소유권이 있는 한 곳에서 전환하고, 소비 컴포넌트는 action callback의 구독만 관리하는 구성이 안전합니다.
자주 틀리는 부분
| 증상 | 원인 | 수정 방향 |
|---|---|---|
| 재활성화 뒤 이벤트가 두 번 호출됨 | OnEnable에서만 구독했습니다. | 대응하는 OnDisable에서 해제합니다. |
| 풀 오브젝트가 비활성인데도 값을 바꿈 | MonoBehaviour를 disabled로만 만들고 코루틴을 남겼습니다. | 코루틴 handle을 OnDisable에서 중단·초기화합니다. |
| 입력 UI를 닫자 게임 입력도 사라짐 | 공유 Action Map을 UI가 직접 disable했습니다. | map 전환의 단일 소유자를 둡니다. |
| 초기화가 여러 번 실행됨 | 1회 초기화를 OnEnable에 넣었습니다. | Awake/Start와 활성 수명 작업을 분리합니다. |
OnEnable/OnDisable은 정리 전용 훅이 아닙니다. 풀링, 씬 재진입, script reload까지 포함한 반복 경로입니다. 구독·등록·코루틴 handle을 한 쌍으로 적고, 다른 컴포넌트가 소유한 전역 상태를 여기서 임의로 켜고 끄지 마세요.
참고 링크
3 sources