RigidBody 없이Collider 끼리만 충돌하면 Trigger 이벤트는 발생하지 않는다. --> 유념할 것
람다식을 사용할 때는 클로저를 유의해야 한다
람다식에 들어가는 메서드가 매개변수를 갖고 있을 경우 이 매개변수는 힙에 복사되어 저장되는데 동일한 변수명을 여러 이벤트에 다르게 등록하고자 한다면 서로 다른 위치를 갖도록 해야한다(반복문으로 i를 넣는 것이 아니라 int num = i 같이 새로 선언한 변수를 사용해야 한다)
✅ 클로저(Closure)란?
클로저는 함수가 생성될 당시의 "외부 변수 환경"을 기억하여, 함수가 생성된 이후에도 그 변수들에 접근할 수 있게 하는 기능입니다.
🧠 쉽게 말해
람다(익명 함수)가 생성될 때 주변의 지역 변수들을 기억해서,
그 함수가 나중에 실행되더라도 변수가 살아있고 변할 수도 있게 해주는 거예요.
📌 예제 1: 간단한 클로저
csharp
복사편집
int counter = 0; Action a = () => Console.WriteLine(counter); counter = 5; a(); // 출력: 5
- () => Console.WriteLine(counter)는 counter를 값이 아니라 변수 자체로 참조.
- 그래서 counter = 5 이후에도 반영됨.
- 람다 내부에 캡처된 counter는 스택이 아니라 힙에 복사된 변수로 동작.
📦 클로저의 동작 방식 (C# 기준)
- 람다 내에서 외부 변수를 참조하면
- 컴파일러는 해당 지역 변수들을 담을 익명 클래스를 생성
- 이 클래스의 필드로 외부 변수들을 복사함
- 람다는 그 클래스를 참조함으로써 변수에 계속 접근 가능
이게 바로 "환경(Env)"을 함께 묶어두는 함수 = Closure.
📌 예제 2: 반복문에서 클로저 문제
csharp
복사편집
for (int i = 0; i < 3; i++) { buttons[i].onClick.AddListener(() => Debug.Log(i)); }
이 경우 i는 같은 참조이기 때문에, 클릭 시점에는 항상 i == 3
해결법:
csharp
복사편집
for (int i = 0; i < 3; i++) { int index = i; buttons[i].onClick.AddListener(() => Debug.Log(index)); }
- 여기서 index는 i의 복사본이라서,
- 람다마다 서로 다른 값을 가짐 → 클로저 문제 해결!
📚 클로저는 어디에 유용한가?
상황설명
| UI 버튼 클릭 이벤트 | 각 버튼마다 고유한 인덱스를 기억 |
| 코루틴에서 지역 변수 유지 | 람다나 익명 함수 내부에서 변수 유지 |
| 타이머/지연 처리 | 나중에 실행되더라도 당시 상태를 기억 |
| DSL, 이벤트 시스템, 콜백 체인 | 상태가 캡처되어 있어야 올바르게 작동 |
🧩 클로저를 사용할 때 주의점
- 클로저로 캡처한 변수는 수명이 늘어나기 때문에 메모리 누수의 원인이 될 수 있음
- 특히 이벤트 등록 후 제거 안 할 경우, 캡처된 변수와 함께 계속 살아있게 됨
- 람다 내에서 값이 변할 수도 있기 때문에, 값 복사 vs 참조 여부에 유의해야 함
✅ 요약
- 클로저는 함수 + 외부 환경(변수) 를 하나의 단위로 캡슐화한 것
- C#에서 클로저는 변수의 값이 아닌 참조를 기억함
- 지역 변수라도 클로저에 의해 힙에 저장되어 수명이 늘어남
- UI 이벤트, 코루틴, 딜레이 처리 등 유니티에서 매우 자주 등장
'[내일배움캠프 Unity 9기]' 카테고리의 다른 글
| 05/16 TIL - 유니티 프로젝트 숙련 강의 수강 (1) | 2025.05.16 |
|---|---|
| 05/15 TIL 프로젝트 마무리 및 Unity 실전 팁 (0) | 2025.05.15 |
| 05/13 TIL c#에서의 구조체와 클래스의 차이 (0) | 2025.05.13 |
| 05/12 TIL - 프로젝트 작업 방향성 (0) | 2025.05.12 |
| 05/09 TIL (0) | 2025.05.09 |