Unity3D中可中途释放的单例

使用静态类,静态变量的坏处是从程序加载后就一直占用内存,想要释放比较麻烦,可是之前使用的单例,没有提供释放的方法,那是不是也同静态的一样直到程序结束菜释放?那单例的好处是什么?

所以此处在单例中加入了可释放的方法来方便释放单例。

用途是:

用此单例管理场景物体时,在不切换场景的前提下释放掉该单例以及挂在单例游戏物体下的子物体

using UnityEngine;

public abstract class SingleBhv<T> : IMono
where T:MonoBehaviour
{
private static T m_instance;
private static object locked;

public static void SetInstance(T instance)
{
m_instance = instance;
}

public static T Instance
{
get
{
if (m_instance == null)
{
m_instance = FindObjectOfType<T>();
}
if (m_instance == null)
{
m_instance = new GameObject("_"+typeof(T).ToString()).AddComponent<T>();
}
return m_instance;
}
set
{
m_instance = value;
}
}

public override void Init()
{
m_instance = this as T;
isInited = true;
}

/// <summary>
/// 释放掉
/// </summary>
public static void Destroy()
{
if (m_instance)
{
GameObject.Destroy(m_instance.gameObject);
}
}
}

public abstract class IMono : MonoBehaviour
{
public bool isInited;

protected virtual void Start()
{
if (!isInited)
{
Init();
}
}

public virtual void Init()
{
isInited = true;
}
}

 

非MonoBeheavier的单例

外部调用以下代码来释放:

XX.Instance = null;

GC.Collect();

或者使用Resources.UnloadUnusedAssets()来释放内存,有时比GC.Collect()更有用!

注意事项:

其他地方不要存放该类的实例,要用该类时就用XX.Instance

using UnityEngine;
/// <summary>
/// single struct
/// </summary>
/// <typeparam name="T"></typeparam>
namespace SingleInstance
{
public class SingleInstance<T> where T : new()
{
public static T m_instance ;
private static Object locked = new Object();

public static T GetInstance()
{
if (m_instance == null)
{
lock (locked)
{
if (m_instance == null)
{
m_instance = new T();
}
}
}
return m_instance;
}

public static T Instance
{
get
{
return GetInstance();
}
set
{
m_instance = value;
}
}
}
}

 

上述代码SingleBhv在使用过程中会有使用不够方便(每次直接调用单例的方法时,有可能还没初始化)和释放内存不及时的问题,所以修改如下:

修改后有两个初始化方法Initial和Init,两个的区别在于Initial是在实例一被创建时就执行,Init则延后到设置参数后调用Init时再执行

using UnityEngine;

public abstract class SingleBhv<T> : IMono
where T : MonoBehaviour
{
private static T m_instance;
private static object locked;
/// <summary>
/// 比Init方法之前检测
/// </summary>
public bool isInitialled;

public static void SetInstance(T instance)
{
m_instance = instance;
}

public static T Instance
{
get
{
if (m_instance == null)
{
m_instance = FindObjectOfType<T>();
InvokeInitial();
}
if (m_instance == null)
{
m_instance = new GameObject("_" + typeof(T)).AddComponent<T>();
InvokeInitial();
}
return m_instance;
}
set
{
m_instance = value;
}
}

private static void InvokeInitial()
{
if (m_instance != null)
{
var instance = m_instance as SingleBhv<T>;
if (!instance.isInitialled)
{
instance.Initial();
instance.isInitialled = true;
}
}
}

/// <summary>
/// 在Init之前调用,并且第一次使用Instance时直接调用,犹如构造函数
/// </summary>
public virtual void Initial(){}
/// <summary>
/// 不同于Initial方法,此方法可以等待Instance各属性初始化完成后再调用
/// </summary>
public override void Init()
{
m_instance = this as T;
InvokeInitial();
isInited = true;
}

/// <summary>
/// 释放掉
/// </summary>
public static void Destroy()
{
if (m_instance)
{
GameObject.Destroy(m_instance.gameObject);
Resources.UnloadUnusedAssets();
}
}
}