关闭Unity Coroutine的正确姿势

Coroutine(协程)作为Unity引擎中的一项有用的特性,在开发中带给我们了很多帮助,但在使用过程中,有一个新人或没有仔细阅读文档的开发者常犯的错误。那就是使用了错误的姿势来StopCoroutine,下面我来进行一番演示:

创建一个脚本:

public class TestCoroutine : MonoBehaviour
{
    IEnumerator CoroutineMethod()
    {
        while (true)
        {
            Debug.Log("Coroutine is running...");
            yield return new WaitForSeconds(1);
        }        
    }
}

有一个每秒打印消息的协程。下面是几种开起的写法:

public void StartCoroutineWithString()
{
    StartCoroutine("CoroutineMethod");
}

public void StartCoroutineWithEnumerator1()
{
    StartCoroutine(CoroutineMethod());
}

public void StartCoroutineWithEnumerator2()
{
    _runningItor = CoroutineMethod();
    StartCoroutine(_runningItor);
}

以及几种关闭的写法:

public void StopCoroutineWithString()
{
    StopCoroutine("CoroutineMethod");
}
    
public void StopCoroutineWithEnumerator1()
{
    StopCoroutine(CoroutineMethod());
}

public void StopCoroutineWithEnumerator2()
{
    if (_runningItor != null)
    {
        StopCoroutine(_runningItor);
        _runningItor = null;
    }        
}

我使用了一个UI进行测试:

关闭Unity Coroutine的正确姿势_第1张图片

读者可先思考一下每种开起方法的关闭方法...

...

...

...

...

下面公布我的测试结果

  StopWIthString StopWithEnumerator1 StopWithEnumerator2
StartWithString YES NO NO
StartWithEnumerator1 NO NO NO
StartWithEnumerator2 NO NO YES

有没有一点suprise??没有的话你就是合格的开发者XD。上面的结果表明,以函数名字符串为参数开起的协程,可以用函数名字符串的形式关闭,可以猜想出,在开启时Unity通过反射获取到成员函数,然后将IEnumerator与函数名建立映射。在关闭时用函数名获取IEnumerator,再关闭。StartWithEnumerator2就是该过程最直接的方式,通过IEnumerator来关闭。至于StartWithIEnumerator1为什么不能关闭?因为使用这样的方法:

StopCoroutine(CoroutineMethod());

是向StopCoroutine()传递了一个新的IEnumerator,并不是StartCoroutine()时传递的对象。因此Unity找不到你所指的是哪个协程。

其实Unity推荐的写法上面的都不是,StartCoroutine其实有一个类型是Coroutine的返回值:

public Coroutine StartCoroutine(IEnumerator routine);
public Coroutine StartCoroutine(string methodName, [DefaultValue("null")] object value);
public Coroutine StartCoroutine(string methodName);
使用
public void StopCoroutine(Coroutine routine);

可以关闭任意形式开起的协程。我们来修改下代码,将开起时返回的Coroutine保存下来,并添加一个使用Coroutine的关闭方法:

public void StartCoroutineWithString()
{
    _runningCoroutine = StartCoroutine("CoroutineMethod");
}

public void StartCoroutineWithEnumerator1()
{
    _runningCoroutine = StartCoroutine(CoroutineMethod());
}

public void StartCoroutineWithEnumerator2()
{
    _runningItor = CoroutineMethod();
    _runningCoroutine = StartCoroutine(_runningItor);
}
...
...
public void StopCoroutineWithCoroutineObj()
{
    if (_runningCoroutine != null)
    {
        StopCoroutine(_runningCoroutine);
        _runningCoroutine = null;
    }
}

更新测试UI:

关闭Unity Coroutine的正确姿势_第2张图片

测试结果不出所料:

  StopWithString StopWithEnumerator1 StopWithEnumerator2 StopWithCoroutineObj
StartWithString YES NO NO YES
StartWithEnumerator1 NO NO NO YES
StartWithEnumerator2 NO NO YES YES

使用Coroutine关闭协程的方式,兼容性广,效率佳,是上上之选!关闭Unity Coroutine的正确姿势_第3张图片

本博客还很年轻,会不时发布一些Unity开发经验和有用的框架组件。读者有任何问题都可以向作者提问,欢迎大家踊跃参与!大家的鞭笞是我成长的动力!谢谢!

你可能感兴趣的:(Unity,Tips)