尝试将 dispatch_async 与 cocos2d 函数一起使用时出错

Posted

技术标签:

【中文标题】尝试将 dispatch_async 与 cocos2d 函数一起使用时出错【英文标题】:errors when trying to use dispatch_async with cocos2d functions 【发布时间】:2014-01-03 01:44:15 【问题描述】:

我正在构建一个滚动菜单,它可以动态生成新的按钮行,并且必须从大量精灵中生成每个按钮。因为这是处理器密集型的,所以每次需要加载新的一行按钮时,菜单都会停留大约四分之一秒。我意识到我需要添加多线程,以便按钮加载可以在与滚动动画不同的线程中处理,但是当我这样做时,它会在尝试加载新按钮时崩溃。这是我正在使用的代码:

-(void)addRowBelow
    _rowIndex--;
    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^
        NSMutableArray *row = [self addRow:_rowIndex];
        [_buttonGrid addObject:row];
        [self removeRow:[_buttonGrid objectAtIndex:0]];
    );
    _nextRowBelowPos += _rowHeight;
    _nextRowAbovePos += _rowHeight;

每次我测试它时都会收到不同的错误,有时是内存错误或断言失败。我怀疑它与异步调用 cocos2d 函数有关?

【问题讨论】:

嗯...多线程和 cocos2d 通常不能很好地用于精灵(以及对其他 cocos2d 对象的操作),因为引擎正在处理它们,而您自己的线程可能正在执行其他操作。您可以在初始化场景中预加载所有精灵,将它们存储在某个容器(模型?)中,然后在需要时将它们带入/取出? 您是在需要时动态创建精灵还是预加载它们?它们是在精灵表中还是在单个文件中?如果可能的话,你的精灵应该在一个精灵表中......它确实节省了 gpu 周期,因为它不必切换纹理输入/输出。 是的,我所有的精灵都在一张精灵表中。绘制调用显示为 1。问题不是精灵本身,而是我需要一次显示的精灵数量以及它们的位置计算。每个按钮包含数百个精灵。我会预先创建精灵对象,并在滚动时简单地显示和隐藏它们,这是个好主意。 【参考方案1】:

您可能会遇到崩溃问题,因为您正在对 cocos 托管对象(精灵、图层、节点等)进行多线程访问。由于引擎希望将这些对象的内部用于显示、GPU 操作等,并且是线程安全的,因此多线程可能不会有好的结果。 您可能正在使用它时更改stuff

动态创建/销毁精灵可能是您放慢速度的原因。 Cocos2d 可以在屏幕上以 60 fps 的速度显示很多(我认为是 2k 左右)对象……只要您不通过大量创建/破坏或 AI 来限制它。

我建议您在场景上台之前预加载所有精灵。您可以在介绍场景或场景本身的初始化中执行此操作,并让精灵归场景所有。然后您可以在 update() 调用期间迭代它们并更改它们的位置,使可见/不可见等。

作为参考,我通常会创建不同的“精灵图层”,将所有精灵加载到场景中。如果我要拥有动态对象,我会尝试预先分配一些并在可能的情况下回收它们。这也让我可以控制屏幕上“什么在什么前面”的顺序(see example here)。每一层还绘制特定“实体类型”的元素,为大量显示赋予一个漂亮的“MVC”字符。

这类似于 iPhone 应用程序回收表格单元格的方式。

仅在您第一次需要它们时创建它们,并在您完全需要它们之前准备好它们。

这有帮助吗?

【讨论】:

是的,这很有帮助。我正在重做整个菜单系统以预加载所有精灵并隐藏当前未显示的精灵。完成后我会回来检查并通知您是否可以解决问题。 不好是低估了它。当你在一个单独的线程上使用它的几乎任何组件时,Cocos2d 都会崩溃。 @LearnCocos2D ;) 我通常会轻描淡写地传递消息……即使消息很重。 我倾向于直言不讳。有时会造成钝器外伤。 :D 太棒了,这完全有效。我重做了菜单,所以它只是在一层的开头加载所有内容,然后上下滚动。事实证明,我什至不需要隐藏屏幕上未显示的精灵 - 屏幕上的精灵显然没有任何性能损失,即使有成千上万的精灵。所以我学到了两件事——那就是不要尝试使用 cocos2d 进行多线程 :-)【参考方案2】:

你可能想要使用的模式是

    将工作分派到后台线程。 (请注意,工作必须安全地在后台线程上执行。) 调度回主线程以更新您的 UI。

以下是代码中的示例:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^

    // Do work that is safe to execute in the background.
    // For example, reading images from disk.

    dispatch_async(dispatch_get_main_queue(), ^

        // Do work here that must execute on the main thread.
        // For example, calling Cocos2D objects' methods.

        NSMutableArray *row = [self addRow:_rowIndex];
        [_buttonGrid addObject:row];
        [self removeRow:[_buttonGrid objectAtIndex:0]];

    );
);

【讨论】:

以上是关于尝试将 dispatch_async 与 cocos2d 函数一起使用时出错的主要内容,如果未能解决你的问题,请参考以下文章

(iOS) dispatch_async() 与 NSOperationQueue

dispatch_async 与 NSOperation 队列

GCD dispatch_async 内部的 NativeX fetchAd 调用。 Phonegap 插件开发

主队列上的 dispatch_sync 与 dispatch_async

比较cocos 2D iphone中的两个字符串

使用 dispatch_async 在 UICollectionView 中加载图片