Search Unity

Question UniTask AsyncLoad list of resources

Discussion in 'Scripting' started by nTu4Ka, Sep 27, 2022.

  1. nTu4Ka

    nTu4Ka

    Joined:
    Jan 27, 2014
    Posts:
    69
    Hi,
    I'm trying to implement async resource loader with UniTask based on example in documentation and got confused how to get the loaded Sprites from LoadResourcesAsync() function.


    Code (CSharp):
    1. public static async UniTask<Sprite[]> LoadResourcesAsync(List<string> resourcePaths)
    2. {
    3.     List<UniTask<Sprite>> SimultaneousLoad = new List<UniTask<Sprite>>();
    4.     foreach (string Path in resourcePaths) {
    5.         SimultaneousLoad.Add(LoadAsSprite(Path));
    6.     }
    7.  
    8.     var loadedResources = await UniTask.WhenAll(SimultaneousLoad);
    9.     // >>> Confusion point 1: Here I can access individual sprites as "loadedResources[0]" for example which is expected <<<
    10.  
    11.     return loadedResources;
    12. }
    13.  
    14. public static async UniTask<Sprite> LoadAsSprite(string path)
    15. {
    16.     var resource = await Resources.LoadAsync<Sprite>(path);
    17.     return (resource as Sprite);
    18. }
    19.  
    20. ...
    21.  
    22. var AsyncLoadedSprites = LoadResourcesAsync(new List<string>(){"Path_1", "Path_2", "Path_3"});
    23. // >>> Confusion point 2: Here I can no longer access individual sprites as "AsyncLoadedSprites[0]" even though I'm returning basically the same value <<<
    24.    
    25.  
     
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,925
    You need to
    await
    the
    LoadResourcesAsync
    .
     
  3. nTu4Ka

    nTu4Ka

    Joined:
    Jan 27, 2014
    Posts:
    69
    Thank you very much! I understood what my mistake was.

    I'm in a bit of a pickle here though. :)

    At some point I need to return instance of a class containing data including loaded sprites.
    And if I need to
    var AsyncLoadedSprites = await LoadResourcesAsyn()
    returning method should be
    async
    and therefore would not be able to return instance of a class.

    Is it possible to return and use something from async function?

    E.g.
    Code (CSharp):
    1. public static async DataClass LoadResourceData() {
    2.  
    3.     LoadedResources = new DataClass();
    4.  
    5.     LoadedResources._Sprites = async LoadResourcesAsync(new List<string>(){"Path_1", "Path_2", "Path_3"});
    6.  
    7.     return LoadedResources; // <--- This won't work since async function can only return void or Task
    8. }
     
  4. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,925
    async
    isn't a return type, it's a keyword that indicates to the compiler that this method runs asynchronously.

    And the answer is in your other methods. Just make the return type UniTask<DataClass>.

    It's worth noting
    async
    and Task/UniTask is just a huge amount of compiler magic that is mostly hidden from you, the user. When you have a return type of Task<T> or UniTask<T> and you return just T, the compiler is wrapping it up in the Task object, and then unwrapping it on the other end.
     
  5. nTu4Ka

    nTu4Ka

    Joined:
    Jan 27, 2014
    Posts:
    69
    Thank you very much spiney199.
    It's clear now.

    I also understood that I need to propagate
    async/await
    to upper layer - to initial caller that doesn't return a value.

    One issue though still remains. One of the callers is the class constructor at top most layer and I cannot make it
    async
    as I understand.
    It seems I need to change something in the architecture.
     
  6. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,925
    Correct. The top-most method is generally
    async void
    , meaning asynchronous but does not return a value. You can also use it for 'fire and forget' methods that operate asynchronously.

    Methods you want to
    await
    on but don't need a return value you use a 'return' type of Task/UniTask, and those you do want a return value you use Task<T>/UniTask<T>.

    Correct. So you will have to do this outside of constructors. It shouldn't be too hard swap a constructor with an
    async void
    Initialise method you introduce yourself.
     
    nTu4Ka likes this.
  7. nTu4Ka

    nTu4Ka

    Joined:
    Jan 27, 2014
    Posts:
    69
    Thank you very much spiney199!
    You completely cleared it out for me.
     
    spiney199 likes this.