zoukankan      html  css  js  c++  java
  • AS3.0中遍历删除容器内子对象的误区。

    有这样一段代码

    代码
     1 var a1:Sprite=new Sprite()
     2 var a2:Sprite=new Sprite()
     3 var a3:Sprite=new Sprite()
     4 var a4:Sprite=new Sprite()
     5 var a5:Sprite=new Sprite()
     6 var a6:Sprite=new Sprite()
     7 var a:Sprite=new Sprite();
     8 a.addChild(a1)
     9 a.addChild(a2)
    10 a.addChild(a3)
    11 a.addChild(a4)
    12 a.addChild(a5)
    13 a.addChild(a6)

    a里面含有6个Sprite;

    当使用for循环函数进行如下循环后

    for(var i:uint=0;i<a.numChildren;i++){
        a.
    removeChildAt(i);
    }

      一直以为a里面的所有子对象都被删除了,最近才发现实际上不是这样。
    执行代码trace(a.numChildren);发现输出的是3,不是0。这说明a里面还有3个对象没有被删除。
    为什么会这样呢?我们来分析下这句循环代码。发现a.numChildren在每次执行完a.removeChildAt(i);后发生了变化,
    每次都减去了一,因为a里面的对象被删除了一个,所以a.numChildren会比原来少1。这样执行了3次循环后a.numChildren变成
    3,i也变成3,3<3不成立退出循环。所以只有深度为0,1,2的被删除了,其他的还在,这样trace(a.numChildren);输出当然是
    3了。

      既然这样把a.numChildren用个变量代替,即代码改为

    var num:uint=a.numChildren;
    for(var i:uint=0;i<num;i++){
        a.removeChildAt(i);
    }

      这样每次循环的时候num就不会发生变化,就是会执行6次循环(a.numChildren=6)。这样应该不会错吧。
    实际上运行时却出现如下错误

    RangeError: Error #2006: 提供的索引超出范围。
        at flash.display::DisplayObjectContainer
    /removeChildAt()
        at _fla::MainTimeline
    /frame1()

      为什么会索引超出范围呢?再次分析下代码。发现num确实是固定不变了,但是a.removeChildAt(i);却出现了问题
    由于as3新的的深度管理机制,当执行第一次循环后,深度为零的对象被删除,深度为1--5的对象的深度会自动减一。
    因此深度为0的位置依然有对象存在。当三次循环后a.numChidlren变成3、i变成3。执行第四循环的时候会报错,因为
    已经找不到索引为3位置的对象了。为了验证这种想法执行下面代码

    代码
    a1.name="a1";
    a2.name
    ="a2";
    a3.name
    ="a3";
    a4.name
    ="a4";
    a5.name
    ="a5";
    a6.name
    ="a6";

    var num
    =a.numChildren;
    try{
        
    for(var i:uint=0;i<num;i++){
            a.removeChildAt(i);
        }
    }
    catch(e){}
    for(var j:uint=0;j<a.numChildren;j++){
        trace(a.getChildAt(j).name)
    }

    分别给a里面每个子对象添加name属性,然后在执行遍历删除后,输出a里面还存在的对象的name。发现输出结果是a2、a4、a6。
    这说明在遍历删除之前深度为奇数的对象被删除了,(为什么只有深度为奇数的对象被删除了,根据as3的深度管理机制揣摩下就能明白了)
      既然as3有这样的深度管理机制,那么不管怎么删除,深度为0位置的始终有对象存在。把代码改成

    var num=a.numChildren;
    for(var i:uint=0;i<num;i++){
        a.removeChildAt(
    0);
    }
    trace(a.numChildren);

    就可以了,可以发现trace的结果是0,说明a里面的子对象全部被删除了。
    注意:千万不要把for(var i:uint=0;i<num;i++)换成for(var i:uint=0;i<a.numChildren;i++),想想为什么?(原理跟上面的一样)
      如果觉得这样写麻烦的话,还可以用下面的写法

    for(var i:uint=a.numChildren;i>0;i--){
        a.removeChildAt(
    0);
    }

    或者写成

    for(var i:uint=a.numChildren;i>0;i--){
        a.removeChildAt(a.numChildren
    -1);
    }

    如果还觉得麻烦的话,还可以这样写

    while(a.numChildren>0){
        a.removeChildAt(
    0);
    }

    实际上我是在看到用while来遍历删除的方法后,才发现我以前用for来遍历删除的问题的,建议大家用最最后一种写法,这样写的代码最简单。

  • 相关阅读:
    缩减apk大小
    android 的安全问题
    android listview 优化
    Python正则表达式指南
    程序员必须知道的几个国外IT网站
    去掉配置项,开发自信的软件
    去掉配置项,开发自信的软件
    Linux防火墙设置
    Linux防火墙设置
    linux下如何使用sftp命令进行文件上传和下载
  • 原文地址:https://www.cnblogs.com/huomiao/p/1635693.html
Copyright © 2011-2022 走看看