Check if an AsyncOperationHandle has been released?

I have always assumed that async operation handle handle.IsValid() will return false if the async operation has been released.

Turns out that’s not the case. If the same asset reference is used in multiple places, handle.IsValid() will return true even if the handle itself is released. Is there any way to check if an async opeation handle has been released?

Currently, I am using a work around extension method and it seems to be working in my case. Yet I still feel like I am not using addressables in its intended way. Is there any built-in method or another usage pattern to solve this issue? Thanks

public static void SafeRelease<TObject>(this ref AsyncOperationHandle<TObject> handle)
{
   if (handle.IsValid())
      Addressables.Release(handle);
   handle = new AsyncOperationHandle<TObject>(); //Force invalid handle
}

Hi @crekri_1 yes using handle.IsValid() is the correct way to check if a handle itself is released. The reason why sometimes the handle is still valid, even though you call Release on it, is because you may have incremented the internal reference count. This value can be viewed by adding a breakpoint and looking at handle.InternalOp.ReferenceCount.

Some reasons an operation’s reference count was incremented:

  • Calling handle.Acquire(). In this case you will need to manually call Release on the operation twice, so that the reference count becomes 0 and the operation is destroyed.
  • Adding a completion callback. We will automatically decrement the reference count when the callback has completed, so you will not need to manually call Release an extra time.

Hi,
We are getting multiple null reference exception while trying to release:

private AsyncOperationHandle m_handle;       
        private void OnDestroy()
        {
            if (m_handle.IsValid())
            {
                Addressables.Release(m_handle);
            }
        }
        private async UniTask LoadPrefab(EpisodeConfig episodeConfig, CancellationToken ct)
        {
            var handle = await LoadAddressable(GetReference(), ct);
            if (m_handle.IsValid())
                Addressables.Release(m_handle);
            m_handle = handle;
            if (m_handle.IsValid() && handle.Result != null)
            {
                            }
            else
            {
                await LoadPrefab(GetSomeOtherInfo(), ct);
            }
        }

this all we have about the handle usage and I wonder if we should set it to null on completion.

Here is the stack:

The docs do not mention that the Completed callback works as a .Release call. Can the docs be clarified perhaps if so? :slight_smile: I am in a situation where I am trying to avoid doing a Release call in an OnDestroy method and instead just rely on the Completed callback.

Is this actually true? I don’t see my reference count going down without calling Release

EDIT: it in fact is NOT true :stuck_out_tongue: If you load the same guid multiple times in the same frame, the first ReleaseOnCompletion will cause the next loads to have their handle.Result to be null. So it is not safe to use. The only safe way to load/release afaik is to check and release each field like this, it’s verbose:

  Addressables.LoadAssetAsync<Item>(newGuid).Completed+=handle=>
            {
                if (this == null)
                {
                    Addressables.Release(handle);
                    return;
                }

                if (handle.OperationException != null)
                {
                    Debug.LogException(handle.OperationException);
                    Addressables.Release(handle);
                    return;
                }

                var item = handle.Result;

                if (item == null)
                {
                    Addressables.Release(handle);                  
                    return;
                }
                    
                // use the result
            };