본문 바로가기
TIL

Unity에서 Find() 함수 사용을 자제해야 하는 이유

by vvin39 2025. 7. 9.

내일배움캠프 64일차 TIL

📌 Find() 계열 함수란?

Unity에서 게임 오브젝트나 컴포넌트를 찾기 위한 대표적인 탐색 함수들

함수  설명 반환 타입
GameObject.Find(string name) 씬 전체에서 이름으로 GameObject 찾음 GameObject
transform.Find(string name) 현재 트랜스폼의 자식 중에서 이름으로 찾음 Transform
GameObject.FindWithTag(string tag) 지정된 태그를 가진 GameObject 찾음 GameObject
GameObject.FindGameObjectsWithTag(string tag) 태그에 해당하는 모든 GameObject 배열 반환 GameObject[]

 

 

🚫 자제해야 하는 이유

1. 성능 문제

  • GameObject.Find()는 씬 내 모든 오브젝트를 순회하며 이름을 비교
  • 게임 오브젝트 수가 많아질수록 검색 비용이 기하급수적으로 증가
  • 특히 Update()나 FixedUpdate()에서 반복 호출 시 프레임 드랍 원인
void Update()
{
    var enemy = GameObject.Find("Enemy");  // 매 프레임마다 전체 탐색? 비효율적!
}

 

2. Null 반환 및 런타임 에러

  • 찾고자 하는 이름이 없으면 null을 반환함
  • 이후 GetComponent 등을 사용할 경우 NullReferenceException 발생
  • 컴파일 타임에서는 에러를 감지하지 못하므로, 런타임에서야 문제를 알 수 있음
GameObject player = GameObject.Find("Player");
player.GetComponent<PlayerController>().Jump();  // player가 null이면 예외 발생

 

3. 유지보수 어려움 (취약한 문자열 의존성)

  • 이름 기반으로 탐색 → 오브젝트 이름이 바뀌면 코드도 함께 수정해야 함
  • IDE 자동 완성 불가능, 리팩터링도 어렵고 버그 추적도 힘듦
  • 협업 중 이름이 변경되면 의도치 않은 버그 유발
// 오브젝트 이름이 "Player_1" → "Player"로 변경되었는데, 코드 미수정
GameObject.Find("Player_1");  // null 반환됨

4. 구조적 결합이 약함 (느슨한 참조)

  • Find()는 오브젝트 간 명시적 관계가 없음
  • 컴포넌트 간 의존성이 드러나지 않아 구조 파악이 어려움
  • 결합도가 낮아져서, 스파게티 코드 발생 가능성 증가

5. 반복 호출 시 문제 심화

  • Find()를 동적 생성 오브젝트에 자주 쓰면 심각한 퍼포먼스 이슈 발생
  • 코루틴, 애니메이션 이벤트, UI 갱신 시에도 반복 탐색은 비효율적

아래 예시는 피해야 함

IEnumerator SpawnLoop()
{
    while (true)
    {
        GameObject target = GameObject.Find("Target");
        target.GetComponent<SomeComponent>().DoSomething();
        yield return new WaitForSeconds(1f);
    }
}

 

✅ 대안 방법 정리

방법  설명  장점
직접 참조 (SerializeField) 에디터에서 드래그 & 드롭 안전, 빠름, 유지보수 용이
태그 기반 탐색 FindWithTag, CompareTag 이름보다 안전하고 빠름
컴포넌트 기반 탐색 GetComponent<T>() / GetComponentInChildren<T>() 명확한 참조 관계 유지
싱글톤 패턴 전역 접근이 필요한 경우 사용 전역 데이터 접근, 성능 보장
Event/Delegate 기반 통신 직접 참조 대신 이벤트로 연결 결합도 낮추며 유연성 확보

 

예외적으로 사용 가능한 경우는?

  • 프로토타입이나 임시 테스트 코드
  • 씬 초기화 직후 단 한 번만 호출하는 경우
  • 태그나 구조가 동적으로 결정되는 경우 (예: 외부 데이터로 결정되는 태그)

하지만 이 경우에도 Find() 사용은 최후의 수단으로 고려해야 함.

 

💬 느낀 점

처음에는 Find()가 간편하고 직관적이어서 자주 썼지만, 프로젝트 규모가 커지고 동시 작업이 늘어나면서 문제점이 명확하게 드러났다. 특히 성능 저하나 디버깅의 어려움을 겪으며 "참조는 항상 명시적으로"라는 원칙의 중요성을 체감했다. 앞으로는 SerializeField나 컴포넌트 기반 탐색을 기본 전제로 삼아야겠다는 다짐을 하게 되었다.

 

🧷 기억 포인트 정리

  • Find()는 느리고 위험한 함수 → 사용 최소화
  • 참조는 직접 연결 (SerializeField) 또는 컴포넌트 방식으로
  • 이름 기반 대신 태그, 타입 기반 탐색을 고려하자
  • 반복 탐색은 절대 피하고, 필요한 경우 1회 캐싱 필수

 

 

 

최근댓글

최근글

skin by © 2024 ttuttak