Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于 ResKit 中 ResLoader 用法上的可能的简化。 #126

Open
Hocchi01 opened this issue Feb 11, 2024 · 1 comment
Open

关于 ResKit 中 ResLoader 用法上的可能的简化。 #126

Hocchi01 opened this issue Feb 11, 2024 · 1 comment

Comments

@Hocchi01
Copy link

目前我看文档的 ResLoader 推荐用法是在每个需要加载资源的脚本中申请 ResLoader 并在销毁时回收:

public class TestResKit : MonoBehaviour 
{
    ResLoader mResLoader = ResLoader.Allocate();
    void Destroy()
    {
	mResLoader.Recycle2Cache();
	mResLoader = null;
    }
}

秉持着减少样板代码的原则(尤其是在某个对象没有销毁事件,但却要为 ResLoader 额外编写 Destroy 方法)
我目前在项目中主要通过静态扩展(未修改 QF 项目代码)实现了用法上的简化:

public class TestResKit : MonoBehaviour, ICanLoadResource
{
    void Func()
    {
        // 某个需要加载资源的地方
        this.GetResLoader().LoadSync<GameObject>(...);
    }
}
  • 附加 ICanLoadResource 接口,通过该接口的静态扩展方法获取 ResLoader
  • 无需在脚本中记录分配的 ResLoader,接口背后自动维护
  • 无需再编写回收代码,gameObject 销毁后自动回收

实现思路:维护一个静态的关于<对象的HashCode,ResLoader>的字典,对象首次调用GetResLoader()方法会为其分配 ResLoader 并记录在字典中,后续调用则从字典中取 ResLoader;销毁时自动回收则是和 QF 中自动注销实现思路一致,为 gameObject 追加专门响应销毁时事件的 Component 并添加回收回调。代码如下:

    public interface ICanLoadResource
    {

    }

    public static class CanLoadResourceExtension
    {
        private static readonly Dictionary<int, ResLoader> _resLoaderDict = new Dictionary<int, ResLoader>();

        public static ResLoader GetResLoader(this ICanLoadResource obj)
        {
            int hashCode = obj.GetHashCode();

            // 对象首次调用 GetResLoader
            if (!_resLoaderDict.ContainsKey(hashCode))
            {
                _resLoaderDict.Add(hashCode, ResLoader.Allocate());

                // 首次调用,若是组件则默认在销毁时注册行为:回收资源引用
                if (obj is Component)
                {
                    var lm = (obj as Component).gameObject.GetComponent<LifecycleModule>();

                    if (!lm)
                    {
                        lm = (obj as Component).gameObject.AddComponent<LifecycleModule>();
                    }

                    lm.OnDestroyed += () =>
                    {
                        if (_resLoaderDict.ContainsKey(hashCode))
                        {
                            _resLoaderDict[hashCode].Recycle2Cache();
                            _resLoaderDict.Remove(hashCode);
                        }
                    };
                }
            }

            return _resLoaderDict[hashCode];
        }
        
        // 用于手动自行注销         
        public static void RecycleResLoader(this ICanLoadResource obj)
        {
            int hashCode = obj.GetHashCode();

            if (_resLoaderDict.ContainsKey(hashCode))
            {
                _resLoaderDict[hashCode].Recycle2Cache();
                _resLoaderDict.Remove(hashCode);
            }
        }
    }

附:其中 LifecycleModule

public class LifecycleModule : MonoBehaviour
{
    public Action OnDestroyed = () => { };
    private void OnDestroy()
    {
        OnDestroyed();
    }
}

可能存在的问题:不同对象的 HashCode 相同的情况,查阅了一些资料,不同对象应该是对应着不同的 HashCode。也可以考虑使用其他唯一性的键值。

@Bian-Sh
Copy link

Bian-Sh commented Feb 11, 2024 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants