这个管理器不含有引用计数功能!
虽然我觉得用了Resource其实用不用引用计数其实没啥影响(反正你也不怎么卸载资源)
事情是这样的,由于我在唐老师上AddressableManeger的课之前就自己写出来了一个AddressableManeger,而后我发现了神奇的一幕。
很奇怪吧,泛型的AsyncOperationHandle能够被存进非泛型的AsyncOperationHandle里面,而且并没有报错,让我感到困惑。
而后看了唐老师的写法,发现是使用父类装子类进行字典存储。但是我不用这种方式依旧可以完成需求(能跑就行)
我开始在群里发问,最终,在蜗牛大神的指引下,我找到了问题的关键所在。
这时我才发现,原来C#的隐式转换也可以进行重载。
时间来到今天。
观看了唐老师的ResourceManeger的课,发现唐老师依旧是使用父类装子类。
我通过AsyncOperationHandle得到了灵感,如果把这个所谓的ResourceInfo类定义一个泛型类和一个非泛型类,再对泛型类重载隐式转换,这样不就可以直接将ResourceInfo<T>存入字典中了吗。
好吧其实是我懒得写as
public class ResourcesInfo
{
public Object asset;
public UnityAction<ResourcesInfo> completed;
public Coroutine coroutine = null;
public bool isDeleting = false;
public ResourcesInfo(Coroutine coroutine,bool isDeleting)
{
this.coroutine = coroutine;
this.isDeleting = isDeleting;
}
public ResourcesInfo()
{
}
public ResourcesInfo<T> Convert<T>() where T : Object
{
ResourcesInfo<T> info = new ResourcesInfo<T>();
info.asset = this.asset as T;
return info;
}
}
public class ResourcesInfo<T> where T : Object
{
public T asset;
public UnityAction<ResourcesInfo<T>> completed;
public Coroutine coroutine = null;
public bool isDeleting = false;
public static implicit operator ResourcesInfo(ResourcesInfo<T> resourcesInfo)
{
ResourcesInfo resources = new ResourcesInfo(resourcesInfo.coroutine, resourcesInfo.isDeleting);
resources.completed += (obj) =>
{
resourcesInfo.asset = resources.asset as T;
resourcesInfo.completed.Invoke(resourcesInfo);
};
return resources;
}
}
于是就有了以上的代码,你会发现,这两个类的成员变量几乎完全相同,这样就可以节省不少代码量。并且能够确保类可以正确的执行逻辑。
当ResourcesInfo<T>向着ResourcesInfo转换的时候,ResourcesInfo的completed委托会增加调用ResourcesInfo<T>中的completed,以确保第一次调用加载方法的顺利执行。
之后就是全部的代码啦,好处就是不需要写一大堆as了。。。。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class ResourcesInfo
{
public Object asset;
public UnityAction<ResourcesInfo> completed;
public Coroutine coroutine = null;
public bool isDeleting = false;
public ResourcesInfo(Coroutine coroutine,bool isDeleting)
{
this.coroutine = coroutine;
this.isDeleting = isDeleting;
}
public ResourcesInfo()
{
}
public ResourcesInfo<T> Convert<T>() where T : Object
{
ResourcesInfo<T> info = new ResourcesInfo<T>();
info.asset = this.asset as T;
return info;
}
}
public class ResourcesInfo<T> where T : Object
{
public T asset;
public UnityAction<ResourcesInfo<T>> completed;
public Coroutine coroutine = null;
public bool isDeleting = false;
public static implicit operator ResourcesInfo(ResourcesInfo<T> resourcesInfo)
{
ResourcesInfo resources = new ResourcesInfo(resourcesInfo.coroutine, resourcesInfo.isDeleting);
resources.completed += (obj) =>
{
resourcesInfo.asset = resources.asset as T;
resourcesInfo.completed.Invoke(resourcesInfo);
};
return resources;
}
}
public class ResourcesManeger : BaseSafeSingleton<ResourcesManeger>
{
private Dictionary<string, ResourcesInfo> resourcesDic;
private ResourcesManeger()
{
resourcesDic = new Dictionary<string, ResourcesInfo>();
}
public void LoadAsnyc<T>(string path,UnityAction<T> callback) where T : Object
{
string resName = path + "_" + typeof(T).Name;
if (!resourcesDic.TryGetValue(resName, out ResourcesInfo info))
{
ResourcesInfo<T> templeInfo = new ResourcesInfo<T>();
templeInfo.completed += (obj) =>
{
callback.Invoke(templeInfo.asset);
templeInfo.completed = null;
templeInfo.coroutine = null;
};
templeInfo.coroutine = MonoManeger.Instance.StartCoroutine(R_LoadAsnyc<T>(path, resName));
resourcesDic.Add(resName, templeInfo);
}
else
{
if(info.asset == null)
{
info.completed += (obj) =>
{
callback.Invoke(obj.asset as T);
};
}
else
{
callback.Invoke(info.asset as T);
}
}
}
private IEnumerator R_LoadAsnyc<T>(string path,string resName) where T : Object
{
ResourceRequest request = Resources.LoadAsync<T>(path);
yield return request;
if(resourcesDic.TryGetValue(resName, out ResourcesInfo info))
{
if (info.isDeleting)
{
Resources.UnloadAsset(info.asset);
resourcesDic.Remove(resName);
}
else
{
info.asset = request.asset;
info.completed?.Invoke(info);
info.completed = null;
info.coroutine = null;
}
}
}
public void LoadAsnyc(string path, UnityAction<Object> callback,System.Type type)
{
string resName = path + "_" + type.Name;
if (!resourcesDic.TryGetValue(resName, out ResourcesInfo info))
{
info = new ResourcesInfo();
info.completed += (obj) =>
{
callback.Invoke(obj.asset);
};
info.coroutine = MonoManeger.Instance.StartCoroutine(R_LoadAsnyc(path, resName, type));
resourcesDic.Add(resName, info);
}
else
{
if (info.asset == null)
{
info.completed += (obj) =>
{
callback.Invoke(obj.asset);
};
}
else
{
callback.Invoke(info.asset);
}
}
}
private IEnumerator R_LoadAsnyc(string path, string resName, System.Type type)
{
ResourceRequest request = Resources.LoadAsync(path);
yield return request;
if (resourcesDic.TryGetValue(resName, out ResourcesInfo info))
{
if (info.isDeleting)
{
Resources.UnloadAsset(info.asset);
resourcesDic.Remove(resName);
}
else
{
info.asset = request.asset;
info.completed?.Invoke(info);
info.completed = null;
info.coroutine = null;
}
}
}
public T Load<T>(string path) where T : Object
{
//更改同步加载逻辑
string resName = path + "_" + typeof(T).Name;
if (resourcesDic.TryGetValue(resName, out ResourcesInfo info) && info.asset == null)
{
MonoManeger.Instance.StopCoroutine(info.coroutine);
info.asset = Resources.Load<T>(path);
info.completed.Invoke(info);
info.completed = null;
info.coroutine = null;
}
else
{
info = new ResourcesInfo();
info.asset = Resources.Load<T>(path);
resourcesDic.Add(resName, info);
}
return info.asset as T;
}
public void Unload<T>(string name) where T : Object
{
string resName = name + "_" + typeof(T);
if (resourcesDic.TryGetValue(name, out ResourcesInfo info))
{
if(info.asset == null)
{
info.isDeleting = true;
}
else
{
Resources.UnloadAsset(info.asset);
resourcesDic.Remove(resName);
}
}
}
public void Unload(string name,System.Type type)
{
string resName = name + "_" + type.Name;
if (resourcesDic.TryGetValue(name, out ResourcesInfo info))
{
if (info.asset == null)
{
info.isDeleting = true;
}
else
{
Resources.UnloadAsset(info.asset);
resourcesDic.Remove(resName);
}
}
}
public void Clear(UnityAction callback)
{
MonoManeger.Instance.StartCoroutine(R_Clear(callback));
}
private IEnumerator R_Clear(UnityAction callback)
{
yield return Resources.UnloadUnusedAssets();
callback.Invoke();
}
}
至于为什么没有引用计数,因为全都是lamda表达式,在进行删除的时候难以去删除这些被加入完成委托队列里的函数,所以就没办法计数啦。
还有,TryGetValue真的特别好用,建议大家都用这个方法,配合C#的一些特性,用的真的特别舒服,但是如果字典中存的是一个委托的话,你要对委托进行增减函数,那么就不能够使用这个方法进行增减