0

I'm working on a big list of buttons and trying to AddListener() for every Button on this list using a quick way

the first way is

btn[0] = CHbutt[0].GetComponent<Button>(); btn[0].onClick.AddListener(delegate { CH(0); });
btn[1] = CHbutt[1].GetComponent<Button>(); btn[1].onClick.AddListener(delegate { CH(1); });
btn[2] = CHbutt[2].GetComponent<Button>(); btn[2].onClick.AddListener(delegate { CH(2); });
btn[3] = CHbutt[3].GetComponent<Button>(); btn[3].onClick.AddListener(delegate { CH(3); });

and it works very well, and AddListener() to all Buttons in btn[]; but a lot of lines...

the second way

for (int i = 0; i < CHmatt.Count; i++)
{
    btn[i] = CHbutt[i].GetComponent<Button>(); btn[i].onClick.AddListener(delegate { CH(i); });
}

but this one is not working, this one AddListener() to only the last button btn[0]

I'm very curious about the difference between these two scripts.

Mohamed Awad
  • 630
  • 1
  • 6
  • 14

1 Answers1

3

It's a capturing issue. Change the code as follows, to avoid capturing i:

for (int i = 0; i < CHmatt.Count; i++)
{
    var ii = i;
    btn[i] = CHbutt[i].GetComponent<Button>(); 
    btn[i].onClick.AddListener(delegate { CH(ii); });
}

What is being passed into AddListener function is a delegate method; however, since you're passing in a loop iteration variable i, the context is captured, and i is actually referenced. As your loop advances, the value of i changes for all captures, therefore making this approach "not work".

By introducing a local copy of i (the name is not material here, I called it ii), which goes out of scope on each loop iteration, the capture of i is avoided, and the actual value of ii is passed to the delegate method (technically, captured, but it's a copy of i for each loop iteration, and therefore does not change as i changes.)

CoolBots
  • 4,770
  • 2
  • 16
  • 30