在最简单的单例模式上遇到了坑。。。这里记录一下,以防以后又忘记了

一般的单线程单例模式,可以用共有方法或者属性去实现全局访问点,这边的话我用的是公有方法

/// <summary>
    /// 单线程单例模式的实现
    /// </summary>
    public class Singleton
    {
        // 定义一个静态变量保存类的实例
        private static Singleton uniqueInstance;

        // 构造函数私有,防止外界创建该类实例
        private Singleton()
        {
        }

        /// <summary>
        /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
        /// </summary>
        /// <returns></returns>
        public static Singleton GetInstance()
        {
            // 判断类实例是否存在,不存在则创建,否则直接返回
            if (uniqueInstance == null)
            {
                uniqueInstance = new Singleton();
            }
            return uniqueInstance;
        }
    }

如果是要支持多线程访问,那么就在获取实例的方法内增加线程锁(lock),具体代码就不写了

然后说一下,我遇到的问题

/// <summary>
    /// 单线程单例模式的实现
    /// </summary>
    public class Singleton :MonoBehaviour
    {
        // 定义一个静态变量保存类的实例
        private static Singleton uniqueInstance;

        // 构造函数私有,防止外界创建该类实例
        private Singleton()
        {
        }

        /// <summary>
        /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
        /// </summary>
        /// <returns></returns>
        public static Singleton GetInstance()
        {
            // 判断类实例是否存在,不存在则创建,否则直接返回
            if (uniqueInstance == null)
            {
                uniqueInstance = new Singleton();
            }
            return uniqueInstance;
        }
    }

我写了一个单例,然后继承自MonoBehaviour,然后里面还有一些数据和代码,这边没有具体写进去,然后遇到的问题是:每次存入数据到这个类里的字典或者字段里的数据,在下次调用的时候都会变成空。

经过代码的断点和debug的调试,发现存入数据后,数据能看到保存进去了,但是再调用GetInstance()方法获取实例时,数据会被清空,uniqueInstance会变为null,就算是你在申明uniqueInstance字段的时候,将它实例化了,也会变为null

具体什么原因,我没有很确定的答案,只能通过调试回避这个问题,看到的大佬知道是啥原因的,也可以给本菜鸡解答一下。

我这边用了两种方法,在继承MonoBehaviour的情况下实现单例

第一种,直接在Awake()方法中赋值,然后公有方法直接返回这个类,为什么不在公有方法中赋值,因为静态方法不能使用this关键字

/// <summary>
    /// 单线程单例模式的实现
    /// </summary>
    public class Singleton :MonoBehaviour
    {
        // 定义一个静态变量保存类的实例
        private static Singleton uniqueInstance;

        // 构造函数私有,防止外界创建该类实例
        private Singleton()
        {
        }
        private void Awake()
        {
        uniqueInstance = this;
        }


        /// <summary>
        /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
        /// </summary>
        /// <returns></returns>
        public static Singleton GetInstance()
        {
            return uniqueInstance;
        }
    }

第二种是修改实例为空时的处理,不再是新new一个,而是去场景中查找,如果没有就添加,然后返回查找到的结果或者添加的脚本

/// <summary>
    /// 单线程单例模式的实现
    /// </summary>
    public class Singleton :MonoBehaviour
    {
        // 定义一个静态变量保存类的实例
        private static Singleton uniqueInstance;

        // 构造函数私有,防止外界创建该类实例
        private Singleton()
        {
        }

        /// <summary>
        /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
        /// </summary>
        /// <returns></returns>
        public static Singleton GetInstance()
        {
        if (uniqueInstance== null)
        {
            //如果uniqueInstance为空,就在场景中查找是否存在此类的实例
            uniqueInstance= FindObjectOfType(typeof(Singleton)) as Singleton;
            //如果uniqueInstance还是为空,就创建一个空物体并添加此类
            if (uniqueInstance== null)
            {
                GameObject obj = new GameObject();
                uniqueInstance= obj.AddComponent<Singleton>();
            }
        }
            return uniqueInstance;
        }
    }

由两个上面连个解决方法猜想,unity的挂在脚本实例化出来的类,和直接new出来的类是有区别的,不能相互之间识别