在使用UGUI的项目中经常遇到诸如
0x0000000140044A66 (Unity) Unity::GameObject::IsActive
0x00000001411B2E73 (Unity) UI::CanvasRenderer::SyncDirtyElements
0x00000001411BFAC9 (Unity) UI::CanvasManager::UpdateDirtyRenderers
0x00000001411BD336 (Unity) UI::Canvas::UpdateBatches
0x00000001411BE11C (Unity) UI::CanvasManager::WillRenderCanvases
0x00000001403B6C8C (Unity) PlayerLoop
0x0000000140B98C3C (Unity) Application::UpdateScene
0x0000000140B9A6F9 (Unity) Application::UpdateSceneIfNeeded
0x0000000140BA0C84 (Unity) Application::TickTimer
0x0000000140DD1197 (Unity) RelaunchUnity
0x0000000140DD277B (Unity) WinMain
0x00000001414EB994 (Unity) read
0x00000000778B59BD (kernel32) BaseThreadInitThunk
的错误,而且最要命的是,一般不在Editor上出现,一般是在iOS、Android真机上小概率随机出现。而一出现就直接游戏崩溃,一发入魂。。
这个问题从unity5.1开始一直困扰到5.3.5p3都没有得到彻底解决,在更新到5.3.5p3后发现该问题居然能在editor出现了。于是花了一整晚时间找这个原因……
根据unity的出错信息,大概猜测是死在了render一个已经销毁的UI element
通过检查代码,发现我们的一个清空Transform下所有子物体的写法如下:
public static void DestroyChildren(Transform transform) {
int childCount = transform.childCount;
for (int i = childCount - 1; i >= 0; --i) {
var go = transform.GetChild(i).gameObject;
GameObject.Destroy(go);
}
transform.DetachChildren();
}
怀疑是Destroy后,Unity存在一个BUG导致CanvasRenderer还继续访问了该物体(已经为NULL)
修改代码如下后,问题解决
public static void DestroyChildren(Transform transform) {
int childCount = transform.childCount;
for (int i = childCount - 1; i >= 0; --i) {
var go = transform.GetChild(i).gameObject;
go.SetActive(false);
//by CG:如果不延迟释放,则会crash:UNITY BUG:UI::CanvasRenderer::SyncDirtyElements
GameObject.Destroy(go, 0.3f);
}
transform.DetachChildren();
}