我正在创建一个AIR应用程序,该应用程序有一个主类,可以创建大量movieclip实例并将它们添加到容器中。在应用程序的整个使用过程中,这些剪辑经常被销毁并创建新的剪辑。
当我创建这些movieclip时,我的主类会向它们添加事件侦听器。电影本身也有事件听众。
每当我更新显示器时,我都会使用以下功能从容器中删除所有这些电影:
for (var i = 0; i < this.mainContainer.numChildren; i++)
{
mainContainer.removeChild(mainContainer.getChildAt(i));
//mainContainer.getChildAt(i)=null;
}
我想知道这是否足以为垃圾收集准备这些实例,即是否会杀死我的主类添加的事件侦听器?或者,在删除每个子项之前,我需要先遍历并删除事件侦听器吗?
另外,取消每个实例在哪里适合呢?上面注释的行给出了错误:
1105: Target of assignment must be a reference value.
谢谢
删除所有子项
您的脚本不会删除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子级的正确方法是向后循环,该循环在给定时刻移除最后一个子级:
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来说,一般的想法是没有来自应用程序范围(附属于阶段的东西和静态类成员)的对这些对象的有效引用。
如果您确信作用域中没有任何内容引用或订阅它们,那么GC将正确地完成其工作。
就我个人而言,我总是编写一个名为destroy(…)的方法,该方法可以删除给定对象中的所有内容:取消订阅所有事件侦听器,将Arrays渲染为长度为0,为每个object类型的变量分配null,删除子级,等等
我也同意Jyreel的观点,依赖显示容器为您保存东西不是程序员的做事方式,但要使用这种方式,或设计更复杂的数据结构,这取决于您和您的理解。
事实上,答案取决于侦听器类型。有两种,"强"one_answers"弱"侦听器,前者需要明确删除,除非在同一对象上侦听,而后者则不需要。它们的不同之处在于,当调用addEventListener()
时,将useWeakReference
参数设置为true表示弱引用,将false(默认值)表示强引用。
举个例子:如果你的MC类在代码中有这个:
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);
}
该监听器已经被代码处理了,但如果您在init()
中说stage.addEventListener(...)
,那么在垃圾收集此类的实例之前,必须明确删除这些内容,前提是监听器没有被声明为"弱"。然而,如果你说添加一个像这样的监听器:
addEventListener(Event.ENTER_FRAME,someFunction);
这些侦听器不需要显式删除就可以收集实例垃圾,即使它们是"强"的,因为它们只代表内部引用,这些引用与它们所引用的对象一起失效。
以下是我在谷歌上发现的内容:"如果被删除的对象是无引用的(没有指向它的引用),那么是的-元素本身由垃圾收集器以及与它相关的任何事件处理程序/侦听器拾取">
就我个人而言,我发现制作一个名为"gameObjects"的精灵,然后添加child(gameObjects),然后制作一个数组,然后执行arrayName.prush(object)比制作容器容易得多,但我从未真正使用过容器。
如果您想要删除事件侦听器的代码,这与添加它们几乎相同,只需将add切换为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-如果要删除事件侦听器所连接的对象,则不需要单独删除它们。我不完全确定,但我认为不应该需要被评论掉的那一行,但我对集装箱一无所知。尝试一堆不同的事情,你就会找到答案。有时,使用一个跟踪("1"),其中1被任何字符串替换,或者使用一个没有引号的变量会有很大帮助。