zoukankan      html  css  js  c++  java
  • Unity单例类

    来源:https://www.cnblogs.com/llstart-new0201/p/9730181.html

    (一)最简单的单利

    复制代码
    public class WebRequestUtility : MonoBehaviour
    {
        public static WebRequestUtility Instance;
    
        private void Awake()
        {
            Instance = this;
        }
    }
    复制代码

    这是最简单有效,最实用最没问题的单利模式。如果说存在什么问题,那就是在别的脚本awake中引用,若果其他脚本中的awake比上述awke先执行,则会报空引用。此问题通过设置脚本执行顺序课解决。题外话,一般初始化启动尽量用start,除非是非常确定要先运行用awake,不要为了先执行而用awake;

    (二)构造函数法

    复制代码
    public class WebRequestUtility : MonoBehaviour
    {
        public static WebRequestUtility Instance;
    
        WebRequestUtility()
        {
            Instance = this;
        }
    
    }
    复制代码

    构造函数中初始化instance最先执行,会在awake之前(官方为找到直接说明,但是鉴于脚本先初始化而后运行,会比awake先执行,事实也是这样,如果有人发现有问题再议,来互怼)。但在2017unity版本中遇到过bug(紧遇到一次),即刚开始运行时,构造函数多次运行,原因未找到。

    (三)DontDestroyOnLoad情况下的单例模式

    有时候单例不能随着场景的加载而消失,需要一直存在,所以需要不能销毁,但是加载时场景中就会存在两个单例(这个说法本身有问题,即本来已经有单例,但是在场景加载时awake又重新运行的情况)

    复制代码
    public class WebRequestUtility : MonoBehaviour
    {
        public bool bDontDestroyOnLoad = false;
    
        public static WebRequestUtility Instance;
    
        private void InitializeInstance()
        {
            if (Instance != null & Instance == this)
                return;
    
            if(bDontDestroyOnLoad)
            {
                if(Instance==null)
                {
                    Instance = this;
                    DontDestroyOnLoad(gameObject);
                }
                else
                {
                    Destroy(gameObject);
                }
            }
            else
            {
                Instance = this;
            }
        }
    
        private void Awake()
        {
            InitializeInstance();
        }
    }
    复制代码

    上述代码参考自unity的NetworkManager组件的源代码。逻辑很简单,只允许有一个单例,引用时,除了保证单例已经初始化(不为空),还要保证单例==this。否则就是单例被重新赋值了,即在别的地方又重新初始化,既然使用单例模式这是不允许的。

    (四)静态属性或者静态方法法

    复制代码
    public class WebRequestUtility : MonoBehaviour
    {
        private static WebRequestUtility instance;
        
        public static WebRequestUtility Instance
        {
            get
            {
                if(instance==null)
                {
                    instance = new WebRequestUtility();
                }
    
                return instance;
            }
        }
    }
    复制代码

    这种也是一种比较好的方法,但是没有(一)(二)简洁,一般用于获取单例时需要再初始化等问题时,对于大部分单例模式(一)(二)已经够用。

    (四)单例模式乱象(真正互怼开始)

    本想再这部分直接开始怼的,但是写到这人戾气已经没了,还是好好学习的好啊,学习让我心平气和。继续说某度出的unity单例的问题。

    1)单例变”多例“

    从他代码角度确实时要单例,但是经过几行代码后变成多例,然后又经过几行代码,然后可从多个事例中return一个”单例“(???),本想直接上链接怼的,想想还是算了。可以看看此文https://blog.csdn.net/qq_15267341/article/details/54232854,多简介,多明了。

    2)使用锁(lock)

    使用锁没有任何问题,但是unity中不推荐使用。再.net中单例模式必须加锁,因为再多线程中统一使用单例会出现冲突等等问题,比如死锁,或者逻辑未理清出问题。但是unity是单线程操作,通过协程来实现“异步“操作,所以不存在此问题。当然也存在开线程的问题,但是开线程或者异步操作只针对纯数据层面的操作,因为在非主线程中是无法进行组件操作的(通俗讲就是操作unity自定义的东西)。所以在unity中异步或者开线程时,基本可以避免在其他线程中调用主线程中的单例情况(针对游戏层面,vr ar来说)。在极少数非要进行相关处理的(一般是在回调时出现),也可以通过在update中实时检测来解决。当然了,如果你的单例不涉及到unity相关组件操作,那也就不用继承mono,就可以用纯C#的语法来处理了。

  • 相关阅读:
    C语言II作业01
    C语言寒假大作战04
    C语言寒假大作战03
    C语言寒假大作战02
    C语言寒假大作战01
    C语言I博客作业12—学期总结
    第一次作业
    C语言I博客作业02
    C语言I博客作业11
    C语言||作业01
  • 原文地址:https://www.cnblogs.com/LiTZen/p/11851116.html
Copyright © 2011-2022 走看看