본문 바로가기

개발/Unity, C#

C# Closure 클로저

 

 

보통 유니티에서 버튼 세팅을 편하게 하려고 반복문을 사용할 때가 있음

 

버튼 5개에

 

    private void SetButton()
    {
        var buttons = GetComponentsInChildren<Button>();

        for (int i = 0; i < buttons.Length; i++)
        {
            buttons[i].onClick.AddListener(() =>
            {
                Debug.Log(i);
            });
        }
    }

 

적당히 이런 식으로 세팅하는 경우가 있는데

 

이러면 결과

 

버튼 하나만 누른 것이 아니라 5개 버튼 하나씩 누른 결과임

 

그럼 왜 이런 결과가 나오냐면

 

기본적으로 메모리에서 힙과 스택의 차이를 알아야 하는데

 

간단하게 넘어가면

 

스택메모리는 코드 영역에서 벗어나면 삭제되고

 

힙 메모리는 참조하는 곳이 없으면 GC가 돌 때 삭제됨

 

 

다시 위로 돌아가서

 

for문에서 i는 포문이 끝나면 삭제되는 변수임

 

하지만 버튼에 람다식으로 이벤트를 추가할 때 i가 포함시킴

 

그래서 i는 스택에 있는 변수였지만 힙에 i의 역할을 하는 변수를 할당하고 그것을 참조하게 됨

 

그 결과 for문이 끝나고 결과인 i = 5가 됨

 

 

해결법

 

    private void SetButton()
    {
        var buttons = GetComponentsInChildren<Button>();

        for (int i = 0; i < buttons.Length; i++)
        {
            int index = i;
            buttons[i].onClick.AddListener(() =>
            {
                Debug.Log(index);
            });
        }
    }

 

int index = i;

 

를 추가하고 index를 참조하면 됨

 

물론 5개의 index가 힙에 할당됨

 

 

결과