我没有出现在线程中加载的图像

时间:2011-10-31 21:19:51

标签: iphone cocos2d-iphone ccscrolllayer

我正在使用CCScrollLayer,我想在玩家选择阶段时准备图像。这很简单但是当我滚动阶段时,它会占用时间(延迟加载图像)。

所以我决定使用NSThread。我收到一条消息“cocos2d:CCSpriteFrameCache:尝试使用来自cocos2d的文件'Level3.png'作为纹理”。那应该出现了。但我在线程上加载的这些图像并不像我想的那样出现。什么都没有。

-(void) moveToStagePage:(int)page
{   
    ... 
    [NSThread detachNewThreadSelector:@selector(prepareTexture:) toTarget:self withObject:[NSNumber numberWithInt:page]];
    ...
}

下面的源代码是准备图像的代码。(线程)

-(void) prepareTexture:(NSNumber*)number
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    int _page = [number intValue];
    NSLog(@"%d Thread start", _page);

    if(loadingTexNum != 0 && (_page + 1) != loadingTexNum)
    {
        [[CCSpriteFrameCache sharedSpriteFrameCache] removeSpriteFramesFromFile:[NSString stringWithFormat:@"Level%d.plist", loadingTexNum]];
        loadingTexNum = _page + 1;
        [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:[NSString stringWithFormat:@"Level%d.plist", loadingTexNum]];
    }

    if(loadingTexNum == 0 && (_page + 1) != loadingTexNum)
    {
        loadingTexNum = _page + 1;
        [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:[NSString stringWithFormat:@"Level%d.plist", loadingTexNum]];
    }

    [NSThread sleepForTimeInterval:10.0];
    NSLog(@"%d Thread release", _page);
    [pool release];
}

3 个答案:

答案 0 :(得分:1)

除非你传递openGL上下文,否则OpenGL不支持在多个线程上加载。

  

Mac OS X进程中的每个线程都有一个当前的OpenGL渲染上下文。每次应用程序调用OpenGL函数时,OpenGL都会隐式查找与当前线程关联的上下文,并修改与该上下文关联的状态。

     

OpenGL不可重入。如果同时从多个线程修改相同的上下文,则结果是不可预测的。您的应用程序可能会崩溃或可能呈现不正确。如果由于某种原因你决定设置多个线程来定位相同的上下文,那么你必须通过在所有OpenGL调用周围放置一个互斥来同步线程,例如gl *和CGL *。阻止的OpenGL命令(例如fence命令)不会同步线程。

Source

你可以在CCTextureCache类中使用- (void) addImageAsync:(NSString *)filename target:(id) target selector:(SEL)selector;,在主线程上调用它。

或者您可以实现自己的,实际上与addImageAsync相同。

供您参考,这是CCTextureCache如何实现加载图像:

 NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];

        // textures will be created on the main OpenGL context
        // it seems that in SDK 2.2.x there can't be 2 threads creating textures at the same time
        // the lock is used for this purpose: issue #472
        [contextLock lock];
        if( auxEAGLcontext == nil ) {
                auxEAGLcontext = [[EAGLContext alloc]
                                                           initWithAPI:kEAGLRenderingAPIOpenGLES1
                                                           sharegroup:[[[[CCDirector sharedDirector] openGLView] context] sharegroup]];

                if( ! auxEAGLcontext )
                        CCLOG(@"cocos2d: TextureCache: Could not create EAGL context");
        }

        if( [EAGLContext setCurrentContext:auxEAGLcontext] ) {

                // load / create the texture
                CCTexture2D *tex = [self addImage:async.data];

                // The callback will be executed on the main thread
                [async.target performSelectorOnMainThread:async.selector withObject:tex waitUntilDone:NO];

                [EAGLContext setCurrentContext:nil];
        } else {
                CCLOG(@"cocos2d: TetureCache: EAGLContext error");
        }
        [contextLock unlock];

        [autoreleasepool release];

答案 1 :(得分:0)

我相信发生的事情是主线程尝试在prepareTexture线程有机会加载纹理之前使用图像。

如果您立即尝试使用新纹理创建精灵,例如在moveToStagePage方法中,那么这将失败。您的线程纹理加载方法将需要标记到已完成加载纹理的其他线程。最简单的方法是简单地切换BOOL变量。只有当纹理加载线程表示已加载纹理时,才应尝试使用这些纹理创建精灵等。

答案 2 :(得分:0)

在单独的线程上加载纹理时,需要使用[[CCTextureCache sharedTextureCache] addImageAsync:texture target:target selector:@selector(onTextureLoaded)];(否则`GLContext会搞乱)。