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.
The docs do not mention that the Completed callback works as a .Release call. Can the docs be clarified perhaps if so? 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 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
};