Yield not working with onClick.AddListener.

Here is a strange behaviour that I found:

function Start()
{
    button.GetComponent(UI.Button).onClick.AddListener( BtnFunction );
}

function BtnFunction()
{
    print("test 1");
    yield WaitForSeconds(1);
    print("test 2");
}

Neither “test 1” nor “test 2” will appear on the console, the code seems not to be executed. But, as a workaround, this would work:

function Start()
{
    button.GetComponent(UI.Button).onClick.AddListener( Temp );
}

function Temp()
{
    BtnFunction();
}

function BtnFunction()
{
    print("test 1");
    yield WaitForSeconds(1);
    print("test 2");
}

Due to the fact that I don’t have a good knowledge of how closure or event or callback should work, I don’t know if it is totally normal or not. But if it is, it would be good to maybe at least throw a Warning to tell that yield are not working inside this function? Because if it is the right behaviour, I’m afraid this question/answer will pop a lot in the future.

My guess is that it’s because BtnFunction is a coroutine, but under the hood none of the button code is calling StartCoroutine to start it so it doesn’t run properly. When you call Temp instead, Temp’s call to BtnFunction generates a StartCoroutine call (as per The Magic Of UnityScript) which is why it works.

Unfortunately I think it’s going to be impossible for addListener to detect when the thing you’re adding is a coroutine.

I don’t know if UnityScript supports the delegate{} construct, but if it does you might be able to wrap it like that.

button.GetComponent(UI.Button).onClick.AddListener( delegate{ StartCoroutine( BtnFunction() ); } );

But what if you need to yield within a delegate? Unity won’t let me.

Still no solution for this problem? I have the same condition, I use delegate and need to yield waitForSeconds, but yield never return.

The solution is the same as if you need to yield inside of Update: You put your yielding code in a separate function, and in your delegate you only call StartCoroutine.