for (int i = 0; i < toggles.Length; i++)
{
toggles[i].btn.onClick.AddListener(() => OnToggle(i));
}
처음 내가 작성했던 코드이다. 코드는 단순해서 따로 설명은 안하겠다..
내가 생각한 대로라면, toggles[0]을 클릭시 OnToggle(0)이 실행되고,
toggles[1]을 클릭시 OnToggle(1)이 실행됐어야 했다.
근데 뜬금없이 button들에서 toggles[5]가 실행되고있었다.
()=> OnToggle(i)
위에서 람다식 안에 들어간 i는 for문에서 사용되는 외부 변수이다.
람다식이 실제 실행되기 이전에는 변수를 참조 형태로 가지고 있다.
버튼들에 들어간 함수는 OnToggle(0), OnToggle(1) 이 아니라
OnToggle(i) 이다. 값이 들어간것이 아니라 i 자체가 참조된것이다.
i는 반복문의 첫번째 사이클에서는 0이었지만,다음에는 1,2,3,4.. 이렇게 자꾸 바뀌는 외부 변수다.
toggles.Length는 5이고, 반복문에 의해 i는 0에서5까지 증가하지만
i < toggles.Length 라는 조건때문에 마지막에는 반복문 안의 함수를 실행하지는 못한 채 탈출한다. (0실행->1실행->2실행->3실행->4실행->5탈출)
이 시점의 i는 5이고, 결국 모든 버튼들에는 OnToggle(5) 가 들어갔던 것이다.
단순하게 반복문 안에 변수를 하나 더 받아서 넣으면 해결이다.
for (int i = 0; i < toggles.Length; i++)
{
var index = i;
toggles[i].btn.onClick.AddListener(() => OnToggle(index));
}
꽤 유명한 문제였다. Closure problem 라고 한다고 한다.
https://stackoverflow.com/questions/271440/captured-variable-in-a-loop-in-c-sharp