I have this function that loads a number of assets via async and I want to call the onComplete
action when all the assets have been loaded but currently given the nature of async I am not sure how to make my function do that as I am relatively new to programming in async.
public void Load(Action onComplete)
{
foreach (var kvp in _db)
{
var key = kvp.Key;
var assetRef = kvp.Value;
assetRef.LoadAssetAsync<TAsset>().Completed += handle =>
{
if (handle.Status == AsyncOperationStatus.Succeeded)
_loadedAssets.Add(key, handle.Result);
//check if all assets have been loaded and then call onComplete
};
}
}
You should use Microsoft's Reactive Framework (aka Rx) - NuGet System.Reactive
and add using System.Reactive.Linq;
- then you can do this:
public void Load2(Action onComplete)
{
(
from kvp in _db.ToObservable()
let key = kvp.Key
let assetRef = kvp.Value
let assetLoader = assetRef.LoadAssetAsync<TAsset>()
from handle in
Observable
.FromEvent<Action<AssetHandle>, AssetHandle>(
h => assetLoader.Completed += h,
h => assetLoader.Completed -= h)
.Take(1)
where handle.Status == AsyncOperationStatus.Succeeded
select new { key, handle.Result }
)
.Subscribe(
x => _loadedAssets.Add(x.key, x.Result),
() => onComplete());
}
Now, that should work. I had to reverse engineer some types, but I think I worked it out. The race condition still exists in your code.