zoukankan      html  css  js  c++  java
  • NGUI List<EventDelegate> 小坑

    NGUI 3.0 之后 采用了 一种 全新的 事件系统 List<EventDelegate> ,使用起来并不麻烦。

    但是最近做项目碰到一个小问题,特此分享一下。

    PS NGUI3.6.4版本

    PS 有空还是看看 源码,有些 时候 光理解 还是没用的。

    一、问题出现在UI 逻辑一块,在一个 UITween 调用之后 要回调一个 事件。

    代码如下:

     1 public class MyTest2 : MonoBehaviour
     2 {
     3     public UITweener tween;
     4 
     5 
     6     List<EventDelegate> list;
     7     public virtual void Start () {
     8         list = tween.onFinished;
     9 
    10         EventDelegate.Add(tween.onFinished, Test);
    11     }
    12 
    13     List<string> list1 = new List<string>();
    14     void Test()
    15     {
    16         Debug.Log(list == tween.onFinished);
    17 
    18         EventDelegate.Remove(tween.onFinished, Test);
    19 
    20         Debug.Log(" Test ");
    21     }
    22 
    23     void OnGUI()
    24     {
    25         if (GUI.Button(new Rect(10, 10, 150, 100), "I am a button"))
    26             tween.PlayForward();
    27         if (GUI.Button(new Rect(10, 110, 150, 100), "I am a button2"))
    28             tween.PlayReverse();
    29     }
    30 
    31 
    32 }

    但是之前 我是 以为  EventDelegate.Remove 这样就能够把 Onfinished 委托给去除的。

    结果我发现不是如此,之后 这个 Tween 每次 调用 结束 之后, Test() 都会执行。

    二、源码分析

    看了下源码。发现问题出在这里:

    这段代码就是 tween 结束后 调用的。

    这里把 mTemp =  OnFinish

    再把 原来的OnFinish 指向了 一个 新 的 new 的 list

    然后在 mTemp  execute 执行完毕 之后 ,再旧瓶装新酒,把mTemp重新装进 OnFinish 这个list.

    来观察一下 Add 的 流程

    我们可以看到 他 使用了 onFinished 的 list , add 了 一个 包含了 test() Callback  的 EventDelegate 

    接下里 执行 的的时候 使用了 同样的 list ,编辑得到 刚才那个  包含了 test() Callback  的 EventDelegate ,然后执行其中的 test()

    同样的 Remove 操作也是如此。

    但是 我们可以看到 tween Execute 的 时候 调用 原来 增加进来的 Test 函数,

    可是在 Test 函数 中 这个时候引用 的 onFinished 已经 变过了。成为了一个新的 new list.并且还没有把 原来的 委托放进来。

    所以这样一来 , 即使你调用 EventDelegate.Remove , 因为 onFinished  list.cout == 0 , 没有 remove  test()

    也就意味着 tween 结束后 会永远调用 test() 。因为在 tween Execute 之后,onFinish 这个 list 才会加入 原来 所有的 委托,这个时候 list.cout 才是1. 重新 加入了 test() 这个时候 remove 才有意义。

    三、解决方法

    但是我感觉 治标 不 治本,如果 我 想 调用 好几次 再 Remove 呢 ? 以后有空 在弄吧。

    其实就是 在 执行的 时候 判断 一下,oneShot 标志位,执行完毕后mTemp 中 remove test(),再放到OnFisish 的时候 test() 就没有了。

     1 public class MyTest2 : MonoBehaviour
     2 {
     3     public UITweener tween;
     4 
     5 
     6     List<EventDelegate> list;
     7     public virtual void Start () {
     8         list = tween.onFinished;
     9 
    10         //EventDelegate.Add(tween.onFinished, Test);
    11         EventDelegate.Add(tween.onFinished, Test, true);
    12     }
    13 
    14     List<string> list1 = new List<string>();
    15     void Test()
    16     {
    17         Debug.Log(list == tween.onFinished);
    18 
    19         //EventDelegate.Remove(tween.onFinished, Test);
    20 
    21         Debug.Log(" Test ");
    22     }
    23 
    24     void OnGUI()
    25     {
    26         if (GUI.Button(new Rect(10, 10, 150, 100), "PlayForward"))
    27         {
    28             Debug.Log(" PlayForward");
    29             tween.PlayForward();
    30         }
    31 
    32         if (GUI.Button(new Rect(10, 110, 150, 100), "PlayReverse"))
    33         {
    34             Debug.Log(" PlayReverse ");
    35             tween.PlayReverse();
    36         }
    37             
    38     }
    39 }

    上结果:

  • 相关阅读:
    各数据库连接maven配置
    在 windows 下配置 git 公共库
    java笔记2(观察者模式、内部类、输入输出)
    linux 常用命令的应用笔记
    Setting Up Google Code And Github With Git
    java笔记3(单元测试中的模式)
    Apache的配置
    Ubuntu安装常用工具
    MongoDB笔记1(安装配置、用户管理、查询与SQL比较)
    Redis的安装与配置
  • 原文地址:https://www.cnblogs.com/chongxin/p/4119754.html
Copyright © 2011-2022 走看看