Mr *_*ons 1 c# unity-game-engine
我正在实例化许多按钮,当点击时需要调用一个函数(通过监听器).但我也经常摧毁它们.这些听众是否也被销毁或者我是否需要删除它们?
例:
public void makeButton()
{
GameObject spawnedButton = Instantiate(prefabButton, prefabButton.transform.position, prefabButton.transform.rotation) as GameObject;
spawnedButton.GetComponent<Button>().onClick.AddListener(()=>
{
listedButtonClicked(someOtherObjectThatWillNotBeDeleted, spawnedButton);
});
}
public void listedButtonClicked(GameObject target, GameObject button)
{
Debug.Log(target);
Debug.Log(button);
}
Run Code Online (Sandbox Code Playgroud)
......所以什么时候spawnedButton被摧毁,这个听众会留下来吗?我正在实例化并删除大量按钮,因此它可能与我相关.
好的,这会有点深入.
考虑一下:
Button button;
void Start()
{
button.onClick.AddListener(Method);
}
void Method()
{
print("Hey");
}
Run Code Online (Sandbox Code Playgroud)
这很好,你的Button组件获得了一个方法的"链接",所以当触发onClick时,它会跳转到Method的地址并从那里运行代码.
第二种情况:
Button button;
void Start()
{
button.onClick.AddListener(Method);
Destroy(this);
}
void Method()
{
print("Hey");
}
Run Code Online (Sandbox Code Playgroud)
注意我销毁当前组件,运行它并触发onClick并且没有问题(?? !!),它打印正常.
第三种情况:
Button button;
string str = "Hey there";
void Start()
{
button.onClick.AddListener(Method);
Destroy(this);
}
void Method()
{
print(this.str);
}
Run Code Online (Sandbox Code Playgroud)
它崩溃了.现在来解释一下.方法总是静态的,编译器(或创建者)足够聪明,可以认为每个实例都不需要拥有自己的方法,而是拥有实例可以自己传递的共享方法模板.
方法如下:
void ClassName.MethodName(this ClassName);
Run Code Online (Sandbox Code Playgroud)
使用实例调用时,此参数将移至前面,并且是非强制性的.该参数实际上可以在方法中使用,因为您可以使用它.同样,它不是强制性的.
因此,在第一种情况下,它可以工作,虽然脚本不再存在,这是因为没有使用任何实例成员.在最后一个示例中,使用了str,并且由于该对象不再存在,因此它会抛出空引用异常.
考虑到另一种方式.
如果创建脚本仍然存在且Button游戏对象或组件被销毁,那么您根本没有风险.清除onClick事件会更明智,但因为它会被破坏,反之亦然.你的产生者在创建所有按钮的循环的下一次迭代中失去了对Button的任何知识:
for(i=0;i<10;i++)
{
GameObject go = null; // new reference added on method stack
go = Instantiate<GameObject>(btnPrefab); // new instance added to reference
} // go connection is lost right here, a new go added to stack in next iteration
Run Code Online (Sandbox Code Playgroud)