防止委托回调中被删除状态的对象

时间:2016-04-23 00:02:19

标签: c# events unity3d delegates

我正在Unity3D中编写一个游戏,我想知道我是应该使用事件 - 还是其他一些构造 - 而不是代表我的网络请求。

在游戏生命周期的某些时刻,我们需要调用REST API并等待其响应。考虑一个UI屏幕,它可以检索朋友列表,并显示朋友的数量以及每个朋友的条目。目前,工作流看起来像这样,使用Action个委托作为我Server类的各种方法的参数:

class FriendsUI : MonoBehaviour
{
    [SerializeField]
    private Text friendCount; // A Unity Text component

    private void OnStart()
    {
        Server.GetFriends(player, response => {
            ShowFriendList(response.friends);
        });
    }

    private void ShowFriendList(List<Friend> friends)
    {
        this.friendCount.text = friends.Count.ToString();
        // Display friend entries...
    }
}

Server.GetFriends方法向我们的REST API发出HTTP请求,获取响应,并调用委托,将响应和控制权返回给FriendsUI

这通常很好用。但是,如果我在调用委托之前关闭了朋友UI屏幕,那么friendCount组件 - 以及该类中的任何其他组件 - 已被破坏,并且NPE会尝试访问它

知道这一点,你认为C#的事件系统是一个更好的设计吗? Server会显示类似FriendsEvent事件的内容,FriendsUI会订阅它。在Server验证/转换了响应时,它会引发事件。 FriendsUI也会自行清理,并在销毁/禁用脚本附加的GameObject时取消注册处理程序。这样,在Server中引发事件时,如果事件处理程序在FriendsUI中不再有效,则不会被调用。

我只是试图在实现它之前在脑中运行它,因为它最终会成为一个有点大的重构。我正在寻找关于人们是否认为这是一条好路线的指导,如果还有其他路线可能会变得更好,以及我可能遇到的任何陷阱。

永远感谢您的时间。

1 个答案:

答案 0 :(得分:2)

只需使用C#delegateevent即可。当从服务器收到朋友列表以订阅该事件时,使每个希望收到通知的脚本。

public class FRIENDSAPI : MonoBehaviour
{
    public delegate void friendListReceived(List<FRINDSINFO> _friends);
    public static event friendListReceived onFriendListReceived;

    //Function that gets friends from the network and notify subscribed functions with results
    public void getFriends()
    {
      StartCoroutine(getFriendsCoroutine());
    }

    private IEnumerator getFriendsCoroutine()
    {
     List<FRINDSINFO> friendsFromNetwork = new List<FRINDSINFO>();

     /*
     NETWORK CODE

     //FILL friendsFromNetwork with Result
     friendsFromNetwork.Add();

     */


     //Make sure a function is subscribed then Notify every subscribed function
      if (onFriendListReceived != null)
      {
        onFriendListReceived(friendsFromNetwork);
      }

     yield return null;
     }
}

然后在FriendsUI课程中,订阅Start()功能并取消订阅OnDisable()功能。您通常会使用OnEnable()功能进行订阅,但有时它不起作用,因为事情并非按时初始化。在Start()功能中执行此操作是修复

public class FriendsUI: MonoBehaviour
{

    void Start()
    {
        //Subscribe
        FRIENDSAPI.onFriendListReceived += onFriendsReceived;

        FRIENDSAPI friendAPI = gameObject.GetComponent<FRIENDSAPI>();
        friendAPI.getFriends(); //Get friends
    }

    public void OnDisable()
    {
        //Un-Subscribe
        FRIENDSAPI.onFriendListReceived -= onFriendsReceived;
    }

    //Call back function when friends are received
    void onFriendsReceived(List<FRINDSINFO> _friends)
    {
        //Do Whatever you want with the result here(Display on the Screen)
    }
}