UE5.1.1中跨类Delegate广播后未触发绑定函数的问题
问题场景
在UE5.1.1开发中,UWebSocketHandler类的OnMessageReceived动态多播代理完成广播后,未触发UCustomGameInstanceBase类中的HandleMessageReceived函数。已确认HandleWebSocketConnected方法正常执行并广播消息,且UCustomGameInstanceBase中的ConnectToWebSocket已完成代理绑定操作。
相关代码
UCustomGameInstanceBase.h
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnMessageReceivedBP, const FString&, Message); UCLASS() class SomeProjectName_API UCustomGameInstanceBase : public UGameInstance { ... UPROPERTY(BlueprintAssignable, Category = "WebSocket") FOnMessageReceivedBP OnMessageReceivedBP; ... void HandleMessageReceived(const FString& Message); };
UCustomGameInstanceBase.cpp
void UCustomGameInstanceBase::ConnectToWebSocket() { if (WebSocketMgr) { WebSocketMgr->OnMessageReceived.AddDynamic(this, &UCustomGameInstanceBase::HandleMessageReceived); WebSocketMgr->ConnectToWebSocket(AccessToken, WSUrl); } } void UCustomGameInstanceBase::HandleMessageReceived(const FString& Message) { UE_LOG(LogTemp, Log, TEXT("HandleMessageReceived!!!")); OnMessageReceivedBP.Broadcast(Message); }
UWebSocketHandler.h
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnMessageReceivedDelegate, const FString&, Message); UCLASS(Blueprintable) class SomeProjectName_API UWebSocketHandler : public UObject { ... UPROPERTY(BlueprintAssignable, Category = "WebSocket") FOnMessageReceivedDelegate OnMessageReceived; ... };
UWebSocketHandler.cpp
void UWebSocketHandler::HandleWebSocketConnected() { ... OnMessageReceived.Broadcast(messageString); }
可能的原因及解决方法
绑定函数未标记为UFUNCTION:Unreal的
AddDynamic依赖反射系统,只有标记为UFUNCTION()的成员函数才能被动态代理正确绑定。修改UCustomGameInstanceBase.h中的函数声明:UFUNCTION() void HandleMessageReceived(const FString& Message);未添加此宏时,绑定会静默失败,无报错但代理不会生效。
对象实例不匹配:确认绑定代理的
WebSocketMgr实例与执行广播的UWebSocketHandler是同一个对象。可在绑定和广播处添加日志打印指针地址验证:// 绑定处(UCustomGameInstanceBase.cpp) UE_LOG(LogTemp, Log, TEXT("绑定代理的WebSocketMgr地址: %p"), WebSocketMgr); // 广播处(UWebSocketHandler.cpp) UE_LOG(LogTemp, Log, TEXT("广播代理的UWebSocketHandler地址: %p"), this);若地址不一致,说明绑定的是其他实例,需检查
WebSocketMgr的初始化逻辑,确保绑定的是后续执行广播的实例。生命周期异常:检查
UCustomGameInstanceBase或UWebSocketHandler的生命周期:- 若
WebSocketMgr在绑定后被销毁重建,原绑定会失效,需在重建后重新绑定代理; - 若
UCustomGameInstanceBase在广播时已被销毁(GameInstance生命周期通常较长,但仍需确认),代理绑定会被自动移除。
- 若
线程安全问题:Unreal动态多播代理默认要求在GameThread执行广播。若
HandleWebSocketConnected在非GameThread调用,需将广播逻辑切换到GameThread:void UWebSocketHandler::HandleWebSocketConnected() { ... AsyncTask(ENamedThreads::GameThread, [this, messageString]() { OnMessageReceived.Broadcast(messageString); }); }可通过
check(IsInGameThread())在HandleWebSocketConnected开头验证当前线程是否为GameThread。绑定时机过晚:确认代理绑定操作在
HandleWebSocketConnected广播之前完成。若WebSocket已连接成功后才执行绑定,此时广播已经发生,只有后续的广播才会触发绑定函数,需调整绑定时机,确保在调用ConnectToWebSocket前完成绑定。
内容的提问来源于stack exchange,提问作者Rasik

