• Unity 协程等待对象的生命周期


      Unity系统提供的协程等待有下面几个 : 

        yield return new WaitForFixedUpdate();
        yield return new WaitForEndOfFrame();
        yield return new WaitForSeconds(1.0f);
        yield return new WaitForSecondsRealtime(1.0f);

      一般情况下我们对协程的生命周期不是很关心, 因为是异步模式的 ( 虽然它不是异步的 ), 不过对于一个需要返回的等待对象, Unity 提供的是一个 class 对象, 比如一个循环等待的协程, 它就会产生很多的 GC 对象, 像下面这样 : 

        IEnumerator TestCoroutine1()
        {
            while(true)
            {
                // ......
                yield return new WaitForEndOfFrame();
                // ......
            }
        }

      而它又只是一个对象, 没有附带其它信息, 那么这个东西其实是可以复用的, 直接给它一个静态对象也是一样的 :

        public static readonly WaitForEndOfFrame WaitForEndOfFrame = new WaitForEndOfFrame();
        IEnumerator TestCoroutine1()
        {
            while(true)
            {
                yield return WaitForEndOfFrame;
                Debug.Log(Time.frameCount);
            }
        }

      然后很多人发现对于 WaitForEndOfFrame 其实返回的对象是空时 ( null ), 得到的结果也一样, 可是其实他们执行代码所在的生命周期是不同的, 可以看看下面的测试结果 : 

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class Test : MonoBehaviour
    {
        int id = 0;
    
        void Awake()
        {
            StartCoroutine(TestCoroutine());
        }
    
        void Update()
        {
            Debug.Log("Update :: " + id++);
        }
    
        void LateUpdate()
        {
            Debug.Log("LateUpdate :: " + id++);
        }
    
        private void OnPostRender()
        {
            Debug.Log("OnPostRender :: " + id++);
        }
    
        IEnumerator TestCoroutine()
        {
            Debug.Log("Coroutine Start :: " + id++);
            int i = 0;
            while(i++ < 3)
            {
                Debug.Log("Coroutine Tick : " + i + " :: " + id++);
                yield return null;
                Debug.Log("Coroutine End : " + i + " :: " + id++);
            }
            this.enabled = false;
        }
    }

      这里使用 null 作为协程返回, 添加了 Update, LateUpdate, OnPostRender 等生命周期, 得到的结果如下 : 

      可见每次 yield 等待之后的代码调用都是在Update之后, LateUpdate之前调用的, 它插入的生命周期就在这里, 而 WaitForEndOfFrame 的就不同了, 就像描述的一样, 是在"一帧"之后才会调用 :

        IEnumerator TestCoroutine()
        {
            Debug.Log("Coroutine Start :: " + id++);
            int i = 0;
            while(i++ < 3)
            {
                Debug.Log("Coroutine Tick : " + i + " :: " + id++);
                yield return new WaitForEndOfFrame();
                Debug.Log("Coroutine End : " + i + " :: " + id++);
            }
            this.enabled = false;
        }

      可以看到插入的生命周期在相机完成渲染之后, 其实是在所有生命周期之后, 所以需要根据实际需求选择正确的返回, 比如你要获取当前帧相机的正确渲染结果, 就需要使用 WaitForEndOfFrame, 而你如果想要改变当前帧的渲染结果, 你就要使用 null 返回, 否则就变成获取到上一帧的渲染结果和改变下一帧的渲染了, 虽然影响不大...

      而 WaitForFixedUpdate 这个在物理帧里的显然使用的就很少了, 它跟逻辑跟渲染都不搭嘎.

      而 WaitForSeconds 跟 WaitForSecondsRealtime 有个决定性的不同, WaitForSeconds 跟 WaitForEndOfFrame 一样只是个简单对象, 而 WaitForSecondsRealtime 有自己的计时器 : 

      所以测试结果 WaitForSecondsRealtime 是无法使用全局对象的 : 

        IEnumerator TestCoroutine()
        {
            var WaitForSecondsRealtime = new WaitForSecondsRealtime(1.0f);
            Debug.Log("Coroutine Start :: " + id++);
            int i = 0;
            while(i++ < 3)
            {
                Debug.Log("Coroutine Tick : " + i + " :: " + id++);
                yield return WaitForSecondsRealtime;
                Debug.Log(Time.realtimeSinceStartup);
                Debug.Log("Coroutine End : " + i + " :: " + id++);
            }
            this.enabled = false;
        }

      它在第一次成功返回之后, 每帧都是成功返回, 没有意义...

      而 WaitForSeconds 还是正常的 : 

        IEnumerator TestCoroutine()
        {
            var WaitForSeconds = new WaitForSeconds(1.0f);
            Debug.Log("Coroutine Start :: " + id++);
            int i = 0;
            while(i++ < 3)
            {
                Debug.Log("Coroutine Tick : " + i + " :: " + id++);
                yield return WaitForSeconds;
                Debug.Log(Time.realtimeSinceStartup);
                Debug.Log("Coroutine End : " + i + " :: " + id++);
            }
            this.enabled = false;
        }

  • 相关阅读:
    html中的marquee属性
    XML处理指令
    h5中的结构元素header、nav、article、aside、section、footer介绍
    IndexedDB:浏览器里的本地数据库
    【我的物联网成长记7】物联网主流通信协议解读【华为云分享】
    还在为运维烦恼?体验云上运维服务,提意见赢好礼!【华为云分享】
    机器学习笔记(八)---- 神经网络【华为云分享】
    【华为云分享】机器学习笔记(七) ---- 贝叶斯分类
    【华为云分享】MongoDB-系统时钟跳变引发的风波
    【Python成长之路】Python爬虫 --requests库爬取网站乱码(xe4xb8xb0xe5xa)的解决方法【华为云分享】
  • 原文地址:https://www.cnblogs.com/tiancaiwrk/p/13384015.html
Copyright © 2020-2023  润新知