一帧mainloop循环中,_compScheduler遍历过程中有comp移除,调用this._zero.fastRemove(comp)移除后,出现遍历下标值递减,造成后续的CCComp执行多次update
这里发的截图,当遍历到i=112时,连续有两个comp移除,第一次移除下标82后,i=111,第二次移除下标80时,i=110。i=111,112这两个comp在同一帧中会调用两次update函数
一帧mainloop循环中,_compScheduler遍历过程中有comp移除,调用this._zero.fastRemove(comp)移除后,出现遍历下标值递减,造成后续的CCComp执行多次update
这里发的截图,当遍历到i=112时,连续有两个comp移除,第一次移除下标82后,i=111,第二次移除下标80时,i=110。i=111,112这两个comp在同一帧中会调用两次update函数
同样的,末尾被塞到插入位置的comp,就不会有update调用了
莫名其妙,cocos提供了api,非要自己写
这是引擎源码,可以去看看
这个写法看起来没问题,把需要移除的内容指向末尾,然后让长度减1,这样就移除了i,算法名字也是快速移除。
写的没问题,用起来有问题
那个remove还有个分支,order不等于0,没有使用fastremove。而且如果组件不使用,可以使用enable进行禁用而不是移除。
用removeAt同样有问题
而且,这里的comp非自定义comp,cc.Label,cc.Button等默认组件都在这里面,节点不用了不可能用enable去禁用。而且源码不管任何形式的操作(Enabled,Disabled)最终都会调到下面有问题的4个函数里
知道严重性了吧
看这个代码,ABCD四个组件,B的Update刚执行完,这时移除B,D被放到B的位置,导致D的Update不会执行?
是的,有可能执行F的update移除A,B,C,后面就都乱套了
可以通过数据驱动设计来解决这个问题,确保在同一帧先操作数据,再直接操作实体。
举个栗子:
const flags = [true, false, true, true];
// 修改组件状态
flags[3] = false
// 同步逻辑
update() {
// 确保所有数据已经修改完毕
// ...
// 进行处理
if (comp.enable && !flags[3]) {
comp.enable = true
flags[3] = true
}
}
这样处理的好处就是,数据在当前帧随便改,改完统一生效。
跟 cocos 的渲染处理机制类似,分为 berforeUpdate 和 afterUpdate。
嗯,修改问题的方式有很多种,你这种就改的比较彻底了。目前只打算把自已确保要每帧update的comp单独拎出来,走额外的分支,确保不会漏掉或者多次执行。
这种问题出现在什么应用场景下。
afk类即时战斗,同一帧多个spine特效移除添加,战斗时间异常,最近各种加日志,追查下来发现是update调用问题(这个问题断断续续查了几个月了 )
这不就是在遍历循环中添加或者删除一项的经典问题
是的,可能是引擎组考虑update性能问题,这里做了一些优化,反而引起了bug