Hold or Wait while Coroutine finishes

In the example below, how can I get FinishFirst() to complete first before running DoLast(), while still retaining the ‘public void StartPage()’ signature?

I’m trying to avoid making “StartPage()” return an IEnumerator as that would force me to change it in the interface. It would be great if my Interface for StartPage() supported both IEnumerator and Void without needing to implement both.

public void StartPage()
{

    print("in StartPage()");
    StartCoroutine(FinishFirst(5.0f));
    DoLast();
    print("done");

}    

IEnumerator FinishFirst(float waitTime)
{

    print("in FinishFirst");        
    yield return WaitForSeconds(waitTime);
    print("leave FinishFirst");
}    

void DoLast()  
{  
    print("do after everything is finished");  
}

I know this is an old question but the popular answer is wrong. It’s using two Coroutines, DoLast is constantly checking to see if FinishFirst is done, and even then there’ll be up to a 100ms delay after FinishFirst completes before DoLast is called.

Why not just call DoLast at the end of FinishFirst? If you don’t know what method will need to be called at the end, you can pass it as an Action parameter:

public void StartPage() {
	print("in StartPage()");
	StartCoroutine(FinishFirst(5.0f, DoLast));
}

IEnumerator FinishFirst(float waitTime, Action doLast) {
	print("in FinishFirst");
	yield return new WaitForSeconds(waitTime);
	print("leave FinishFirst");
	doLast();
}

void DoLast() {
	print("do after everything is finished");
	print("done");
}

You would need to do “yield return StartCoroutine…” and have StartPage return IEnumerator. StartPage cannot return void in this case.

You could either call DoLast() after the yield in the FinishFirst function or you could make DoLast a coroutine too with a loop that yields while the FinishFirst coroutine is running.

Something like:

bool inFirst = false;

public void StartPage() {
 
   print("in StartPage()");
   StartCoroutine(FinishFirst(5.0f));
   StartCoroutine(DoLast());
   print("done");
}

IEnumerator FinishFirst(float waitTime) {
   inFirst = true;
   print("in FinishFirst");        
   yield return new WaitForSeconds(waitTime);
   print("leave FinishFirst");
   inFirst = false;
}

IEnumerator DoLast() {

   while(inFirst)       
      yield return new WaitForSeconds(0.1f);
   print("Do stuff.");
}

Much late, but if you want to check if a coroutine had finished or not instead of waiting and then run the next code sequentially, other than the obvious way of declaring an additional boolean flag you can use setup the IEnumerator type variable instead of doing StartCoroutine( on the method directly. (Which is the same, since the method returns IEnumerator.

This variable is useful for StopCoroutine, but if you set that variable to null at the end of the coroutine it can doubles as a way to check if a coroutine ended or not by null checking it.

I use this so players cannot input while the story is advancing. For example, defines :

private IEnumerator advanceStoryDelayRoutine;
IEnumerator AdvanceStoryDelayRoutine()
{
	yield return new WaitForSeconds(3.5f);
	advanceStoryDelayRoutine = null;
}

When using it

		//this check is necessary for the first time or StopCoroutine will stop to nothing, resulting in a run time error
		if(advanceStoryDelayRoutine != null) 
		{
			StopCoroutine(advanceStoryDelayRoutine);
		}
		advanceStoryDelayRoutine = AdvanceStoryDelayRoutine();
		StartCoroutine(advanceStoryDelayRoutine);

And then the input code can check against this variable

	if(advanceStoryDelayRoutine != null)
	{
		//still hasn't finished yet
	}

Here’s a simple extension class I wrote that adds a callback to UnityWebRequest.Send.

    public static class NetworkingUtils
    {
        public static void Send(this UnityWebRequest request, MonoBehaviour behavior, Action onFinished)
        {
            behavior.StartCoroutine(routine(request,onFinished));
        }
        
        private static IEnumerator routine(UnityWebRequest request, Action onFinished)
        {
            yield return request.Send();
            if (request.isError)
                Debug.LogError(request);
            else
            {
                Debug.Log("Results for " + request + ":

" + request.downloadHandler.text);
onFinished();
}
}
}
Then you can use it by passing an action in to Send that will get called on completion. You’ll also need to stick in a Monobehaviour so the coroutine works.

request.Send(monoBehavior, ()=>print("Done"));

You’ll probably want to modify it to do more with errors (a different callback perhaps).

One approach that is not discussed here is outlined clearly in this excellent overview of Coroutines:

It is possible to execute a
nested coroutine and to wait for its
execution to be completed. The
simplest way to do this, is by using
yield return:

IEnumerator A()
{   
    // Waits for B to terminate
    yield return StartCoroutine( B() );
}