在AS3中,从阶段移除子级是否会删除对它的所有引用,以便可以由垃圾收集器对其进行清理?

问题描述 投票:0回答:3

我正在创建一个AIR应用程序,该应用程序具有一个主类,该主类创建许多动画片段的实例并将其添加到容器中。在整个应用程序的使用过程中,这些剪辑经常被破坏并创建新的剪辑。

创建这些影片剪辑时,我的主类向它们添加事件侦听器。电影剪辑内部还具有事件侦听器。

每当更新显示时,我都会使用以下功能从其容器中删除所有这些动画片段:

        for (var i = 0; i < this.mainContainer.numChildren; i++) 
        {
            mainContainer.removeChild(mainContainer.getChildAt(i));
            //mainContainer.getChildAt(i)=null;
        }

我想知道这是否足以为垃圾回收准备那些实例,即是否杀死了我的主类添加的事件侦听器?还是我需要先删除事件监听器,然后再删除每个孩子?

而且,将每个实例的null放在哪里适合呢?上面注释掉的行给出了错误:

1105: Target of assignment must be a reference value.

谢谢

actionscript-3 null garbage-collection removechild
3个回答
2
投票

删除所有孩子

您的脚本不会删除mainContainer的所有子项,而是仅删除一半。为什么?因为每次您删除一个孩子,其余的都会关闭以吞噬释放的索引,因此您的脚本将其删除,如下所示:

Initial picture  :  0 1 2 3 4 5 6 7 8 9
Remove child at 0:  1 2 3 4 5 6 7 8 9
Remove child at 1:  1 3 4 5 6 7 8 9
Remove child at 2:  1 3 5 6 7 8 9
Remove child at 3:  1 3 5 7 8 9

从给定容器中删除ALL子项的正确方法是backward循环,该循环在给定时刻删除最后一个子项:

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

while循环,在有任何深度时删除深度为0的子代:

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

但是,有一种更简单的方法来清空容器(可从Flash Player 11及更高版本使用:]

mainContainer.removeChildren();

垃圾收集器

对于GC,总的想法是,应用程序范围(附加到stage的对象和静态类成员)没有对这些对象的有效引用。

如果您确定范围内没有任何内容引用或订阅它们,则GC将正确执行其工作。

我个人总是编写一个称为destroy(...)的方法,该方法可消除给定对象内的所有内容:取消订阅所有事件侦听器,将Array呈现为0,分配null] >应用于每个Object类型的变量,删除子级,等等。>>

我也同意Jyreel

,依靠显示容器为您保存内容不是程序员的处理方式,而是使用这种方式或设计更复杂的数据结构,该决定取决于您和您的理解。

以下是我在Google上找到的内容:“如果删除的对象是无引用的(没有指向它的引用),那么是的-垃圾收集器以及与之关联的任何事件处理程序/侦听器都会拾取元素本身”

我个人发现制作一个名为“ gameObjects”的精灵,然后创建addchild(gameObjects),然后制作一个数组,然后执行arrayName.push(object)比制作一个容器要容易得多,但是我从来没有真正使用过容器。

如果您想要删除事件监听器的代码,则与添加它们几乎相同,只是使用remove切换添加。

这是使用数组和子画面来完成您要尝试做的事情所需的代码的粗略概念,但是如果您发现容器更简单,则只需忽略此部分:

private var gameObjectsArray:Array;
private var gameObjects:Sprite;
public function Start(){
            gameObjects = new Sprite();
            addChild(gameObjects);
            gameObjectsArray = new Array();
            var myObject:object = new object();
            gameObjects.addChild(object);
            gameObjectsArray.push(object);
}

如果不是游戏,则只需将“ gameObjects”替换为所需名称,然后将“ object”替换为创建,修改并添加到数组的实例。

TL:DR-如果要删除事件侦听器所连接的对象,则无需分别删除事件侦听器。我不太确定,但是我认为不需要注释掉的行,但是我对容器一无所知。尝试多种不同的方法,您将找到答案。有时使用trace(“ 1”)并将1替换为任何字符串,或者使用不带引号的变量会有很大帮助。

实际上,答案取决于侦听器类型。有两个侦听器,即“强”侦听器和“弱”侦听器,除非侦听同一对象,否则前者需要明确删除。通过将useWeakReference参数设置为true表示弱,将false设置为false(默认)以获取强引用,将useWeakReference参数设置为不同。

示例:如果您的MC类在代码中包含此代码:

addEventListener()

该侦听器已经由代码处理过,但是您应该在public function Example1() { .... if (stage) init(); else addEventListener(Event.ADDED_TO_STAGE,init); } private function init(e:Event=null) { removeEventListener(Event.ADDED_TO_STAGE,init); } 中说stage.addEventListener(...),必须将这些类显式删除,然后再对此类的实例进行垃圾回收,前提是该侦听器未声明为“弱”。但是,如果您说添加这样的侦听器:

init()

即使这些侦听器是“强壮的”,也不必显式删除这些侦听器以收集实例垃圾,因为它们仅表示内部引用,这些引用与引用的对象一起无效。


0
投票

以下是我在Google上找到的内容:“如果删除的对象是无引用的(没有指向它的引用),那么是的-垃圾收集器以及与之关联的任何事件处理程序/侦听器都会拾取元素本身”


0
投票

实际上,答案取决于侦听器类型。有两个侦听器,即“强”侦听器和“弱”侦听器,除非侦听同一对象,否则前者需要明确删除。通过将useWeakReference参数设置为true表示弱,将false设置为false(默认)以获取强引用,将useWeakReference参数设置为不同。

© www.soinside.com 2019 - 2024. All rights reserved.