使用for进行removeChild的问题

碰到一个奇怪的问题,最后终于解决。其实是自己的疏忽。记在这里了:

下面的代码中,vs是一个ViewStack实例,removeVS的功能是移除VS中多余的子显示对象,以便对其中的子显示对象进行重建。在vs中原来有4个子显示对象copyright、step1、step2、stepUpload,它们不在移除范围之内。

 1private function removeVS():void{
 2    Logger.info('removeVS运行,删除前的vs子数量:{1}', vs.numChildren);
 3    for(var i:int=0; i < vs.numChildren; i++)
 4    {
 5        Logger.debug('当前序号:{1}',i);
 6        var __step:UIComponent = vs.getChildAt(i) as UIComponent;
 7        var __isInitStep:Boolean = __step == copyright || __step == step1 || __step == step2 || __step == stepUpload;
 8        Logger.info('当前的step name:{1},是否保留:{2},当前序号{3}', __step.name, __isInitStep, i);
 9        if(!__isInitStep)
10        {
11            vs.removeChild(__step);
12        }
13    }
14    Logger.info('removeVS运行,删除后的vs子数量:{1}', vs.numChildren);
15}

在没有添加子显示对象之前,vs的子显示对象应该有4个,而一旦添加的其他的显示对象,当调用removeVS的时候,却只能移除一个添加的显示对象!

例如:我在vs中添加了一个step3和step4显示对象,在移除的时候,却仅仅移除了step3,而step4仍然保留!!!

这是怎么回事?经检查,发现问题出在vs.numChildren上。

因为for循环中引用的是vs.numChildren,而当__inInitStep为false的时候,vs移除了一个子显示对象。这时vs.numchildren就发生了变化,变为vs.numchildren-1。这导致循环少执行了一次,没有删掉step4。

找到了问题的原因,修改成如下代码:

 1private function removeVS():void{
 2    var __toRemovedArr:Array = new Array();
 3    for(var i:int=0; i < vs.numChildren; i++)
 4    {
 5        Logger.debug('当前序号:{1}',i);
 6        var __step:UIComponent = vs.getChildAt(i) as UIComponent;
 7        var __isInitStep:Boolean = __step == copyright || __step == step1 || __step == step2 || __step == stepUpload;
 8        if(!__isInitStep)
 9        {
10            __toRemovedArr.push(__step);
11        }
12    }
13    for each(var k:UIComponent in __toRemovedArr)
14    {
15        vs.removeChild(k);
16    }
17}

2011-09-26更新:还有更新简单的两个办法

  1. 使用递减的for循环
  2. 使用while循环

详见评论中的回复1和回复4