Unity의 UI Button에 onClick 이벤트를 반복문 내에서 동적으로 할당하여 사용할 때 발생한 문제.
문제 상황 발생의 소스 코드
private void Test()
{
List<Button> buttonList = new List<Button>();
int max = 3;
for (int i = 0; i < max; i++)
{
GameObject buttonObject = new GameObject("Button_" + i);
buttonList.Add(buttonObject.AddComponent<Button>());
}
for (int i = 0; i < max; i++)
{
Debug.Log(buttonList[i].name + "\tAdd OnClick Event");
buttonList[i].onClick.AddListener(() =>
{
Debug.Log(i);
});
}
for (int i = 0; i < buttonList.Count; i++)
{
buttonList[i].onClick.Invoke();
}
}
원하는 결과는 아래 3개의 Log에서 0, 1, 2 순서로 출력되어야 하는데 반복문에서 사용된 변수의 값의 최종값만 출력하게 되는 것 같아보였다. 이러한 상황에서 문제가 되는 상황은 List나 Array에 해당 값을 넣어서 접근하게 되면 out of range 가 일어나는 상황이다.
변경된 소스 코드
//for (int i = 0; i < max; i++)
//{
// Debug.Log(buttonList[i].name + "\tAdd OnClick Event");
// buttonList[i].onClick.AddListener(() =>
// {
// Debug.Log(i);
// });
//}
for (int i = 0; i < max; i++)
{
int index = i;
Debug.Log(buttonList[i].name + "\tAdd OnClick Event");
buttonList[i].onClick.AddListener(() =>
{
Debug.Log(index);
});
}
for 문에의 증감에 사용된 변수를 다시 for 문 안에서 지역 변수로 할당하여 사용하면 문제가 없었다.
C# 람다 식을 사용하면 컴파일 시에 람다 함수내의 변수와 코드를 임시 클래스로 만들어서 사용한다고 한다.
즉, for 문에서 선언된 int i 는 임시 클래스의 멤버 변수로 선언 되고 해당 변수를 for 문 내에서 참조하여 사용하기 때문에 최종적으로 Log를 찍는 순간에는 for문의 증감문이 전부 적용되어 int i 는 3이 되었고 해당 변수를 동일하게 참조하고 있기 때문에 3의 값으로만 출력되는 것이다.
'Unity Engine' 카테고리의 다른 글
ScriptableObject AssetBundle 참조 및 불러오기 실패 문제 (0) | 2021.03.17 |
---|---|
UGUI Text Typing 스크립트 (Rich Text 중첩 지원) (0) | 2020.02.21 |
UnityWebRequest: Delete Request DownloadHandler NULL (0) | 2019.08.07 |
Unity Android Build: AndroidManifest Multiple 시 OBB파일을 불러오지 못하는 문제 (0) | 2019.06.27 |
UnityWebRequest: SetRequestHeader Cookie 문제 (0) | 2019.05.16 |