关于在Unity开发中使用事件系统时报空而出现bug的修复(无缘无故报空!消失的成员变量!)

       ​​​​​

         本文章可能适合给开发稍微大型的项目提供一个遇到类型bug时的解决方案。大概情景是在运行项目后,其中一个脚本中的非静态成员变量在上一秒还是存在的,在下一秒就无缘无故的变为null,并且怎么都找不到有销毁此成员变量和更改此成员变量的语句,从而使得程序无法继续执行下一步所写的功能。

出现的错误:MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it.

        这个问题的具体情景是:题主设计了一个给人物换装和移动转向的脚本,将移动转向的方法进行了事件注册(由字典和委托存储),其中在人物选择面板中用到人物换装的方法,在游戏场景中用到人物换装和移动转向的方法。而当题主运行项目,由人物选择面板过场景进游戏场景时,在游戏场景中,经过调试,上一秒还有值的成员变量,下一秒就变为null。

        为防止太抽象,先给出题主的有关代码:

        这是注册事件的代码:

 private Dictionary<Type,IEventRegistration> eventRegistrationsDict=new Dictionary<Type,IEventRegistration>();  //不直接用字符串而用结构体(Type)来做字典有这几点考虑,第一是安全:字符串在输入错误的时候并不会显示编译错误,其没有编译检查。第二是性能更好:结构体是值类型,存储在栈上,不需要额外的堆内存,减少垃圾回收的压力。而且其也不会装箱拆箱

 public void Regist<T>(Action<object> onEvent)
 {
     var type=typeof(T);
     IEventRegistration registration;
     if(eventRegistrationsDict.TryGetValue(type, out registration))
     {
         (registration as EventRegistration).OnEvent += onEvent;
     }
     else
     {
         registration = new EventRegistration()
         {
             OnEvent = onEvent 
         };
         eventRegistrationsDict.Add(type, registration);
     }

 }

 public void Send<T>(object obj) where T : new()
 {
     var type= typeof(T);
     IEventRegistration registration;
     if(eventRegistrationsDict.TryGetValue(type,out registration))
     {
         (registration as EventRegistration).OnEvent.Invoke(obj);
     }
 }

       经过各个检查,题主发现出错部分就在有关委托的报空上,正常的逻辑上说,注册好一个事件,到合适的时候使用,这有什么错呢?

        下面,让题主用简单的语言讲述出错过程。我在A物体挂载的A脚本上用A事件存储A方法,过场景后,销毁A物体,并在B物体挂载的A脚本上用A事件存储A方法。此时,事件系统中,A事件存储了两个同样的A方法,这两个同样的方法在事件被调用的时候都会被触发。而因为前一个A方法所依赖的A物体被销毁了,它并不会使用B物体挂载的A脚本的非静态成员变量,使得直接报空。

        至此,原因找到了,那就是委托方法所依赖的物体被销毁,但是此委托方法并没有被释放,使得另一个委托方法调用时,也要调用此没有依赖的委托方法,而其中使用到的非静态成员变量无效,变为null。解决办法,要么是销毁此物体时同时释放这个委托方法;要么是在用这个委托方法时进行非静态成员变量是否为null的判断,然后才安全的执行方法。

        而进行判断后再执行方法的话,其实有损性能,因为这个没有依赖的委托方法已经没有用了,但是每次事件触发时都会调用此方法,为了性能,可以的话选择另一种更为合适,当然也有其他应情况考虑的办法。这个就由具体情况具体分析了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值