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.

Need advice on handling Coroutines

Discussion in 'Scripting' started by antx, Jan 13, 2016.

  1. antx

    antx

    Joined:
    Feb 16, 2012
    Posts:
    28
    I need to load data via WWW and for that I start a coroutine. Since the calling method continues after the start of the coroutine I can not handle the result (loaded data, errors...) right there.
    So the calling method has to end there and my coroutine has to notify my program somehow that it is done.

    What I want to know is how to do this in a clean way.

    - Call another function at the end of the coroutine?
    - Trigger an event somehow and have a function listening on that?
    - Poll for a flag via Update?

    Right now I call a function but this means that the coroutine is still around until the execution of the funciton is done. Is there something like a best practice for working with coroutines?
     
  2. Fajlworks

    Fajlworks

    Joined:
    Sep 8, 2014
    Posts:
    344
    If you need a simple solution, you could use closures:
    Code (CSharp):
    1. IEnumerator MyWWWSequence( string url, System.Action<WWW> callback )
    2. {
    3.      WWW www = new WWW( url );
    4.      yield return  www;
    5.    
    6.      if (callback != null)
    7.           callback( www );
    8. }
    Now you simply do:
    Code (CSharp):
    1. string url = "http://images.earthcam.com/ec_metros/ourcams/fridays.jpg";
    2.  
    3. StartCoroutine( MyWWWSequence(url, (www) =>
    4. {
    5.      Renderer renderer = gameObject.GetComponent<Renderer>();
    6.      renderer.material.mainTexture = www.texture;
    7. }));
    Do note there are other ways to do this, but I find it the most elegant way, because the followup logic is right under the call, instead in a function located somewhere else in the code. Hope it helps!
     
  3. Immanuel-Scholz

    Immanuel-Scholz

    Joined:
    Jun 8, 2013
    Posts:
    221
    A co-routine in general is a very low-level technical implementation tool that you can use for a vast variety of scenarios and things. So for general co-routine usage, there is no simple answer to the question. Its a bit like asking "What are best practices of using a while loop" :D

    For specifically loading WWW data, everything is fine. This doesn't sound like something you do on a thousand objects in parallel, so "polling every frame" should have no measurable performance penalty (if it had at all...).

    Everything goes, just do what fits to the rest of your coding style.

    Still not satisified? Then... dice rolling sound... call a member function of the behaviour. :D
     
  4. Munchy2007

    Munchy2007

    Joined:
    Jun 16, 2013
    Posts:
    1,716
    I often handle this kind of thing with a callback.

    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class NewBehaviourScript : MonoBehaviour {
    6.  
    7.     // Use this for initialization
    8.     void Start () {
    9.         Debug.Log("Coroutine started...");
    10.         StartCoroutine(DoStuff(result => {
    11.             Debug.Log(result);
    12.         }));
    13.  
    14.         Debug.Log("This will print before the coroutine finishes...");
    15.     }
    16.  
    17.     // Update is called once per frame
    18.     void Update () {
    19.  
    20.     }
    21.  
    22.     IEnumerator DoStuff(System.Action<string> callback)
    23.     {
    24.         yield return new WaitForSeconds(10f);
    25.  
    26.         if(callback != null)
    27.             callback.Invoke("Coroutine finished!");
    28.     }
    29. }
    30.  
    Edit: Fajlworks beat me to it with a better example :)
     
  5. antx

    antx

    Joined:
    Feb 16, 2012
    Posts:
    28
    Okay, thanks a lot guys. Callbacks seam to be a good way to react to coroutine results. The fact that the code is together in one place is great. Also that one can specify the callback function when the coroutine gets started is nice too.

    However for my special case I will use events, since my callback code is complex and involves up to two more coroutine calls which then would need a callback too. I think this code would be very unreadable at the end.

    I just was wondering if there was a kind of ultimate way to do it.

    Thanks again!