How to AddListener() (from code) featuring an argument for multiple buttons?
Hi ! I have some problem with loading prefab and with that loading add listners for my prefab. The prefab have 4 buttons. Here's code that I use:
GameObject go = (GameObject)Instantiate(Resources.Load("Prefab"));
Button[] buttons = go.GetComponentsInChildren<Button>();
for (int i = 0; i < buttons.Length; i++)
{
buttons[i].onClick.AddListener(() => { eventManager.answerSelection(i); });
}
eventMangaer Is my script with button logic.
My problem is that when I click buttons, there is execption with index 4 at all buttons.
Answer by cjdev · Jan 05, 2016 at 02:17 AM
What's happening is that when you create a lambda expression (a delegate, which is what the event listener is) and you "capture" or include an outside variable you are actually including a pointer to that variable's location in memory. In other words, everything you do to the original, outside variable will be reflected in the logic inside the lambda expression. Practically speaking, to get around this you can instantiate a temp variable in your for loop like this:
Button[] buttons = go.GetComponentsInChildren<Button>();
for (int i = 0; i < buttons.Length; i++)
{
int temp = i
buttons[i].onClick.AddListener(() => { eventManager.answerSelection(temp); });
}
This way you are creating a temporary variable whose only outside scope is the one iteration of the for loop and so you can use it without fear of accidental external modification.
Thanks man. That cost me half a day. Will google for a way to avoid lambda expressions at all cost!