Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Weird behaviour when using button.onClick.AddListener

Discussion in 'UGUI & TextMesh Pro' started by agame, Mar 4, 2015.

  1. agame

    agame

    Joined:
    Mar 4, 2015
    Posts:
    1
    Hi,

    I'm trying to add a listener function to buttons on runtime.

    On 'Awake()' or 'Start()' I have tried the following:

    m_buttons is a list of buttons. (assume size of 4)

    Code (CSharp):
    1.  
    2. for(int i=0;i<m_buttons.Count;++i)
    3. {
    4.             m_buttons[i].onClick.AddListener(delegate{this.OnSelect(m_buttons[i]);});
    5. }
    6.  
    the issue here is that I get index out of range error when clicking the buttons.

    However, the following (should be functionally the same) works without problems:

    Code (CSharp):
    1.  
    2. m_buttons[0].onClick.AddListener(delegate{this.OnSelect(m_buttons[0]);});
    3. m_buttons[1].onClick.AddListener(delegate{this.OnSelect(m_buttons[1]);});
    4. m_buttons[2].onClick.AddListener(delegate{this.OnSelect(m_buttons[2]);});
    5. m_buttons[3].onClick.AddListener(delegate{this.OnSelect(m_buttons[3]);});
    6.  

    Another issue I have is the following:

    (Assume each button has a different name: ex. button1,button2, button3, button4)
    Code (CSharp):
    1.  
    2. OnSelect(Button sender)
    3. {
    4.   Debug.Log(sender.name);
    5. }
    6.  
    Doing this:
    Code (CSharp):
    1.  
    2. foreach(Button b in m_buttons)
    3. {
    4.    b.onClick.AddListener(()=>OnSelect(b));
    5. }
    6.  
    Makes every button I press log the name of the last button in the list (Button4).

    I have used the above in a different project with no problems, not sure why this is happening. If anyone has any insights on what the cause may be please let me know, thanks!

    **I tested the above in blank project just to be sure nothing else is interfering, but I am still getting the same problems. Is this a bug??

    **using Unity 4.6.0 f3 (OS X)
     
    Last edited: Mar 4, 2015
  2. SimonDarksideJ

    SimonDarksideJ

    Joined:
    Jul 3, 2012
    Posts:
    1,683
    I've seen this once before and never got to the bottom it. Could be a mono compiler issue.
    I'd log it to be on the safe side and ensure the team know to check it out.
     
  3. CastleIsGreat

    CastleIsGreat

    Joined:
    Nov 10, 2014
    Posts:
    176
    This has happened to me as well, it has to do with the lambda of the for and foreach statements, I still have yet to understand whats going wrong, so I typically work around using it in that form.
     
  4. noony

    noony

    Joined:
    Jun 1, 2010
    Posts:
    2
    The reason this is happening is because the loop variable that's passed to the anonymous function is declared outside the loop, so will always hold its last value when the function is eventually called post-loop. If you declare another variable inside the loop to capture its current state when the function is declared, it should work fine e.g.
    Code (CSharp):
    1.  
    2. foreach(Button b in m_buttons)
    3. {
    4.     Button b2 = b;
    5.     b2.onClick.AddListener(()=>OnSelect(b2));
    6. }
    7.  
     
    Emilian0 and DannyHerbert like this.
  5. Dameon_

    Dameon_

    Joined:
    Apr 11, 2014
    Posts:
    542
    First off, in your for loop, change ++i to i++. The two are functionally different. Look up the difference, and you'll understand why you're getting an index out of range error.
     
  6. Dariyoh

    Dariyoh

    Joined:
    Nov 30, 2013
    Posts:
    2
    While you are right about pre and post increment being different, it actually makes no difference which one you use in a for loop. (This is because the evaluation and incrementation is decoupled).

    But as noony already pointed out this is not a bug, but due to the access of a modified closure.