When UserWidget is garbage collected, In ConditionalBeginDestroy On UObject, ObjectFlags change RF_BeginDestroyed
In next Step, BeginDestroy On UserWidget, RemoveFromParent function starts
Through Engine Version 4.19 → 4.20, RemoveFromParent Check !HasAnyFlags(RF_BeginDestroyed)
So, Isn’t RemoveFromParent call meaningless on BeginDestroy? And
If World and LocalPlayer are destroyed on EndPlayMap, what should we do if SWidget’s resources are not released?
Thank you in advance!!
void UUserWidget::BeginDestroy()
{
Super::BeginDestroy();
//TODO: Investigate why this would ever be called directly, RemoveFromParent isn’t safe to call during GC,
// as the widget structure may be in a partially destroyed state.
// If anyone ever calls BeginDestroy explicitly on a widget we need to immediately remove it from
// the the parent as it may be owned currently by a slate widget. As long as it’s the viewport we’re
// fine.
RemoveFromParent();
// If it’s not owned by the viewport we need to take more extensive measures. If the GC widget still
// exists after this point we should just reset the widget, which will forcefully cause the SObjectWidget
// to lose access to this UObject.
TSharedPtr SafeGCWidget = MyGCWidget.Pin();
if ( SafeGCWidget.IsValid() )
{
SafeGCWidget->ResetWidget();
}
}
void UUserWidget::RemoveFromParent()
{
if (!HasAnyFlags(RF_BeginDestroyed))
{
if (FullScreenWidget.IsValid())
{
TSharedPtr WidgetHost = FullScreenWidget.Pin();
// If this is a game world add the widget to the current worlds viewport.
UWorld* World = GetWorld();
if (World && World->IsGameWorld())
{
if (UGameViewportClient* ViewportClient = World->GetGameViewport())
{
TSharedRef WidgetHostRef = WidgetHost.ToSharedRef();
ViewportClient->RemoveViewportWidgetContent(WidgetHostRef);
if (ULocalPlayer* LocalPlayer = GetOwningLocalPlayer())
{
ViewportClient->RemoveViewportWidgetForPlayer(LocalPlayer, WidgetHostRef);
}
FWorldDelegates::LevelRemovedFromWorld.RemoveAll(this);
}
}
}
else
{
Super::RemoveFromParent();
}
}
}