I’ve create a manager class deriving from Game Instance Subsystem to provide access to creating, finding and joining sessions using the Online Subsystem.
However I discovered that the delegates that the OS interface provides don’t seem to be unregistered when using lambdas and the respective delegates rather than delegate handles.
Here’s the code:
OnlineSubsystem = IOnlineSubsystem::Get();
const IOnlineSessionPtr SessionPtr = OnlineSubsystem->GetSessionInterface();
SessionPtr->OnCreateSessionCompleteDelegates.AddLambda([&](FName SessionName, bool Successful)
{
// class custom multicast delegate
OnCreateSessionCompleted.Broadcast(Successful);
if (const IOnlineSessionPtr SessionPtr =
OnlineSubsystem->GetSessionInterface())
{
// piece of code that seems not to unregister the delegate
SessionPtr->ClearOnCreateSessionCompleteDelegates(this);
}
});
The delegate is fired correctly when session is created, but if the function is called again it will fire as many times as it has been called. However if I use delegate handles and clear using delegate handles everything works as expected.
I cannot seem to find this function anywhere in any of the engine versions, but I’m gonna assume the void* Object parameter it takes is meant to be used to clear all delegates bound to that specific Object.
Problem is, lambdas are not bound to a specific object. Even if you capture this via the capture mechanism, code has no way to retrieve it for comparison.
You need to use object-bound delegate method. AddStatic and AddLambda will not work. AddWeakLambda might do the job.
Thanks for the clear explanation and solution as it worked. I saw also that many examples use a delegate handle to clear bound objects. Do you mind explaining what are the advantages of the delegate_handle compared to the typical delegate ? Since the sessions interface provides both types.
Well in this case handles are useful if you want to bind (and later clear) to a non-object bound function, such as a static or a regular lambda.
In general, handles can also be useful for several use cases :
you can bind a multicast delegate multiple times within the same object, and then you only want to clear one of them.
you can use IsValid() to check is a specific delegate handle is bound or not.
you can use Reset() to clear a delegate handle. Most of the time objects do not provide a “ClearAllDelegates” function like you are using here, so storing all delegate handles into an array gives you an easy way to clear all of them at some point.