产业气象站|【厚积薄发】Addressable卸载单个资源的疑问


产业气象站|【厚积薄发】Addressable卸载单个资源的疑问
文章图片
这是第213篇UWA技术知识分享的推送 。 今天我们继续为大家精选了若干和开发、优化相关的问题 , 建议阅读时间10分钟 , 认真读完必有收获 。
UWA问答社区:answer.uwa4d.com
UWAQQ群2:793972859(原群已满员)
Addressable卸载单个资源的疑问
如何判断硬件支持GPUInstance
StringBuilder反射实现String报错
Unity2018RequireES3.1+AEP有什么作用
Unity打包AssetBundle闪退
Addressable
Q1:通过Addressable加载的PrefabA , 里面引用了SpriteA , 现在通过Addressable加载SpriteB , 把SpriteA释放 , 替换为SpriteB 。
这时候SpriteA无法通过Addressable.Releases释放 , 提示Addressables.Releasewascalledonanobjectthataddressableswasnotpreviouslyawareof.Thusnothingisbeingreleased 。
如果不释放SpriteA , 只是引用改为SpriteB , 那么在释放PrefabA的时候是否会正常释放SpriteA呢?
A1:Addressable内的Load和Release是配对调用的 , 第一步Load了PrefabA , 对内部的SpriteA是Dependency引用 , 没走Load流程 , 自然无法通过Release释放 , 可以考虑 , PrefabA不要直接挂SpriteA , 也是通过运行时去LoadSpriteA再挂 , 然后就可以在需要的时候Release掉再替换B了 。
这里的细节是:
调用LoadAssetAsync时会调用TrackHandle , 给Load的Completed事件添加一个OnHandleCompleted处理 , 这个处理内会将Load方法返回的Handle给保存到m_resultToHandle , 在Release的时候去找这个Handle , 并调用这个Handle.Release方法来做实际的Release操作 。
产业气象站|【厚积薄发】Addressable卸载单个资源的疑问
文章图片
找不到 , 自然就报题主的错误了 。
Q2:PrefabA不引用SpriteA , 运行时再加载的方式会导致在编辑器非运行时无法看到图片 , 对于拼UI的同事会不太方便 。 我考虑的方案是 , 记录当前资源是否运行时加载的 , 只有是才调用释放 , 但是不确定原来的SpriteA失去引用后 , 是否能在PrefabA释放时正常释放SpriteA 。
A:我想一般来说你也是把PrefabA实例化以后使用 , 那么2种情况:
1.使用系统的Object.Instantiate , 这时就和Addressable没什么关系了 。 SpriteA在切换时直接Destory就行了 。
2.使用Addressables.ReleaseInstance , 那么系统会去调用AsyncOperationBase.DecrementReferenceCount , 当引用计数为0时 , 调用ResourceManager内部类的InstanceOperation.Destroy方法 , 最终调用到InstanceProvider.ReleaseInstance , 这时你会发现系统其实也是简单的Object.Destroy而已 。
产业气象站|【厚积薄发】Addressable卸载单个资源的疑问
文章图片
那么我们可以这样理解 , 对于PrefabA实例化出来的对象 , 由Addressbles管理 , 需要调用ReleaseInstance来释放 , 当没有引用的时候 , 系统Destroy它 , 那么对于该对象内部的引用资源SpriteA , 其实并不是Addressable管理的那一层级 。
最后整理一下:
对于自己Instantiate出来的对象 , SpriteA随便什么时候都可以Destroy , 和一般Unity对象做法一样 。
对于通过Addressable实例化出来的对象 , 则可以在需要切换Sprite的时候 , 调用Destroy方法释放SpriteA , 然后载入并设置SpriteB 。
SpriteB如果使用Addressable来实例的 , 则在ReleaseInstance这个PrefabA实例化出来的对象前先调用ReleaseInstance方法释放SpriteB 。
如果SpriteA的图片资源并不在PrefabA所在AssetBundle包内 , 那么是作为依赖被载入的 , 理论上也是要在PrefabA实例被Release后 , 发现没有引用的情况下才Unload , 也就是说 , 提前DestroySpriteA并不会释放它所用资源和AssetBundle包 。


推荐阅读