在做项目时遇到了一个需求,是需要从碰撞体中获取某个组件,并对该组件做一些操作,因此我编写了如下代码:
private void OnTriggerEnter2D(Collider2D collision)
{
var csr = collision.GetComponent<SpriteRenderer>();
if (csr != null)
{
// Do Something
}
}
不过,csr作为一个临时变量会引发GC,Visual Studio就为我提供了这样的建议:
原来,Unity中提供了TryGetComponent()这一方法,可以尝试从目标gameobject获取一个组件,如果获取失败,就不会为其申请空间,这样一来就减少了GC的发生,我的代码于是变成了这样:
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.TryGetComponent<SpriteRenderer>(out var csr))
{
// Do Something
}
}
我就想,即便是这样,我仍旧会产生一个临时变量csr用来存储get到的组件,那么如果我把这个csr声明为一个全局变量,会不会直接就避免了GC?(当然也不合理,因为这样一来在我们没有使用这个变量的大部分时间里,这部分内存都要被占用着)当时没想这么多,就这么做了,于是代码又变成了这样:
private SpriteRenderer csr;
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.TryGetComponent(out csr))
{
// Do Something
}
}
这下连泛型都省了,因为变量的类型已经被指定了。
马上我就继续去写其他的业务代码,结果发现事情没有那么简单,在我从别处调用了csr后,发现它居然是空的!
事实证明,out的返回值并不是用于长期留存的,Unity可能在这个方法执行完后就会把这块内存给清空,进而导致了csr成了一个空引用。。。
最后,我还是接受了创建临时变量的事实,把临时变量的值赋给了csr:
private SpriteRenderer csr;
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.TryGetComponent(out SpriteRenderer tsr))
{
csr = tsr;
// Do Something
}
}
再次尝试,csr的引用内容终于正常了。以后在处理out参数的时候,肯定会多留个心眼了。