RT,本篇博客记录的是马三的一次解决 LuaFunction has been disposed 的bug的全过程,事情还要从马三的自研框架 ColaFrameWork 说起。最近,马三在业余时间维护了一款基于Unity的客户端自研框架,起名叫 ColaFrameWork ,寓意是希望写代码能像喝小可乐一样享受和轻松。为了在Lua层可以监听到UI事件,马三制作了UGUIEventListener、UGUIDragEventListenner和UGUIMsgHandler等这样几个UI组件,其中 UGUIEventListener和UGUIDragEventListenner这种Listener组件实现了IPointerDownHandler、IPointerClickHandler和ISubmitHandler这样的UGUI IEventSystemHandler UI事件接口,并且实现了接口定义的方法,然后在 UGUIEventListener中暴露出来一些 onClick、onDrag、onSubmit这种委托字段出来。在UI实例化的时候,代码会把这些监听器的脚本动态地绑定到UI预制体上面,然后再将Lua层的onClick、onDrag等这些方法动态地与Listener暴露出来的委托字段进行绑定。这样,当我们触发了UI的事件的时候,就会执行Listener中预先实现了相关接口的方法,而我们又在这些方法中调用了我们的委托,接着在通过lua虚拟机触发Lua层的function,从而实现了Lua层对UI事件的监听,之后我们也就可以很方便地在Lua层进行业务逻辑的开发了。
大概地工作原理就先讲到这里,毕竟我们这篇博客主要是记录如何解决 LuaFunction has been disposed这个bug的,知道一些基本的东西就OK了,关于UGUIEventListener、UGUIDragEventListenner和UGUIMsgHandler等这样几个UI组件的一些细节和实现原理等相关内容,马三会在后续的博客中进行进一步的讲解。同时马三也有计划待 ColaFrameWork 框架大概成型和稳定以后,将整个框架按照流程与模块进行分篇地讲解与解读,形成一系列的博客供大家交流学习,好的稍微有点扯远了,我们言归正传,说说这个bug。
上面的组件在实际使用中会偶现 LuaFunction has been disposed 这个bug,它经常出现于我们在UnityEditor中停止运行游戏的时候,虽然看起来没有影响游戏的正常运行,但是毕竟这个error信息在控制台看着也很讨厌,而且为了我们框架的稳定性也应该及时地解决到这个bug。在经过进一步地测试以后,马三发现了在只点击UI上面的button组件之后,再执行关闭游戏并不会出现这个报错信息,而当在我们点击或者使用了InputFiled组件之后,再关闭游戏则会100%地重现出这个问题。知道了如何复现问题,就好办了,下一步我们着手分析一下这个问题是如何出现的,并且尝试干掉它。
上面说的UGUIEventListener组件的简化版代码如下:
1 public class UGUIEventListener : MonoBehaviour, 2 IMoveHandler, 3 IPointerDownHandler, IPointerUpHandler, 4 IPointerEnterHandler, IPointerExitHandler, 5 ISelectHandler, IDeselectHandler, IPointerClickHandler, 6 ISubmitHandler, ICancelHandler 7 { 8 void Start() 9 { 10 11 } 12 public delegate void UIEventHandler(GameObject obj); 13 public UIEventHandler onClick; 14 public virtual void OnPointerClick(PointerEventData eventData) 15 { 16 if (CheckNeedHideEvent()) 17 { 18 return; 19 } 20 if (null != onEvent) 21 { 22 this.onEvent("onClick"); 23 } 24 if (this.onClick != null) 25 { 26 this.onClick(gameObject); 27 } 28 } 29 }