Выполнение действия над подклассом CCSprite

Пожалуйста, потерпите меня, я собираюсь опубликовать длинный код. Я создаю подкласс CCSprite:

@interface Character : CCSprite {
    }
    -(id) initWithTexture:(CCTexture2D*)texture rect:(CGRect)rect;
    @end

    @implementation Character
    -(id) initWithTexture:(CCTexture2D*)texture rect:(CGRect)rect
    {
        NSLog(@"in initWithTexture");
        if( (self=[super initWithTexture:texture rect:rect]))
        {
        }
        return self;
    }
    -(void) dealloc
    {
        NSLog(@"character dealloced");
        [super dealloc];
    }
    @end

Вопрос №1: это правильно?

У меня есть слой, содержащий этот спрайт как переменную класса, а также еще один CCSprite.

Character *characterSprite;
CCSprite *burpSprite;

Этот слой также имеет два объекта CCAnimation:

CCAnimation *burpAnim;
CCAnimation *burpParticlesAnim;

В этом классе у меня есть два метода: -(void) loadBurpAnimation; -(void) unloadBurpAnimation;

-(void) loadBurpAnimation {
        NSString* burpFile;
        NSString* burpFilePVR;

        NSString* burpParticlesFile;
        NSString* burpParticlesFilePVR;

        burpFile = @"latestBurp1-1.plist";
        burpFilePVR = @"latestBurp1-1.pvr.ccz";
        burpParticlesFile = @"burpParticles1-1.plist";
        burpParticlesFilePVR = @"burpParticles1-1.png";

        [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:burpFile texture:[[CCTextureCache sharedTextureCache] addImage:burpFilePVR]];
        [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:burpParticlesFile texture:[[CCTextureCache sharedTextureCache] addImage:burpParticlesFilePVR]];

        NSMutableArray *burpFrames = [NSMutableArray array];
        for(int i = 231; i <= 268; ++i) {
            [burpFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:@"burp.%d.png", i]]];
        }
        burpAnim = [[CCAnimation alloc] initWithFrames:burpFrames delay:0.04f];
        [burpFrames removeAllObjects];

        //Burp Particles
        [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:burpParticlesFile];
        NSMutableArray *burpParticlesFrames = [NSMutableArray array];
        for(int i = 3; i <= 37; ++i) {
            [burpParticlesFrames addObject:[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:[NSString stringWithFormat:@"Burp_%05d.png", i]]];
        }

        burpParticlesAnim = [[CCAnimation alloc] initWithFrames:burpParticlesFrames delay:0.04f];
        [burpParticlesFrames removeAllObjects];
}

-(void) unloadBurpAnimation {

    [burpAnim release];
    [burpParticlesAnim release];
}

Мне нужно загрузить анимацию отрыжки в поток и вызвать метод в основном потоке для ее воспроизведения, который выглядит следующим образом:

-(void) loadAnimation {
    NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];

    [dictLock lock];

    if( [EAGLContext setCurrentContext:auxEAGLcontext] ) {
        [self loadBurpAnimation];
                [self performSelectorOnMainThread:@selector(burpAnimation) withObject:nil waitUntilDone:NO];
        } else {
        CCLOG(@"cocos2d: TetureCache: EAGLContext error");
    }
    [dictLock unlock];
    [autoreleasepool drain];
}

Я знаю, что есть способ загрузить анимацию отдельно "asynchAddImage", но здесь это не проблема.

-(void) burpAnimation {

    CCAction *burpAction = [CCSequence actions:
                            [CCAnimate actionWithAnimation:burpAnim restoreOriginalFrame:NO],
                            [CCCallFunc actionWithTarget:self selector:@selector(animationDone)],nil];
    CGSize winSize = [CCDirector sharedDirector].winSize;
    characterSprite = [[Character alloc] initWithSpriteFrameName:@"burp.231.png"];
    characterSprite.position = ccp(winSize.width/2, winSize.height/2);
    [characterSprite setScale:1.5];

    CCAction *particlesAction = [CCSequence actions:
                            [CCAnimate actionWithAnimation:burpParticlesAnim restoreOriginalFrame:NO],
                            nil];
    burpSprite = [[CCSprite alloc] initWithSpriteFrameName:@"Burp_00003.png"];
    burpSprite.position = ccp(winSize.width/2-50, winSize.height/2-80);

    [self addChild:characterSprite];
    [characterSprite release];

    [self addChild:burpSprite];
    [burpSprite release];

    [characterSprite runAction:burpAction];
    [burpSprite runAction:particlesAction];
}

Настоящая проблема, с которой я сталкиваюсь, заключается в том, что селектор CCCallFunc вызывается после анимации:

- (void)animationDone {
    //Here characterSprite retain count is 2
        NSLog(@"B4 stop char rc %d", [characterSprite retainCount]);

        [characterSprite stopAllActions];

        //Here characterSprite retain count is still 2
        NSLog(@"B4 stop char rc %d", [characterSprite retainCount]);

    [self removeChild:characterSprite cleanup:YES];

>>>     //Here characterSprite retain count is 1 WHY?
>>>     NSLog(@"char rc %d", [characterSprite retainCount]);

        //Here burpSprite retain count is 2
        NSLog(@"particles rc %d", [burpSprite retainCount]);

    [burpSprite stopAllActions];

        //Here burp retain count is 1
        NSLog(@"particles rc %d", [burpSprite retainCount]);
    [self removeChild:burpSprite cleanup:YES];

        // releases the animation objects
    [self unloadBurpAnimation];

        //Here burpAnim retainCount = 1
        NSLog(@"BURP ANIM rc = %d", [burpAnim retainCount]);

        //Here burpParticlesAnim retainCount = 0 , crashes if print here obviously.
        //NSLog(@"Particles ANIM rc = %d", [burpParticlesAnim retainCount]);

        [[CCSpriteFrameCache sharedSpriteFrameCache] removeUnusedSpriteFrames];
    [[CCTextureCache sharedTextureCache] removeUnusedTextures];
}

Две проблемы: несмотря на то, что я удалил спрайт персонажа, я получаю его счетчик сохранения, равный единице. Несмотря на то, что я выпустил burpAnim, я получил его счетчик сохранения, равный единице, из-за этого CCSpriteFrameCache не может удалить spriteFrames, и, следовательно, текстура также не удаляется.

Обе эти проблемы как-то взаимосвязаны? Спасибо, ребята, что прочитали это, любая помощь очень ценится.


person Asymptote    schedule 15.01.2011    source источник


Ответы (1)


Две проблемы: несмотря на то, что я удалил спрайт персонажа, я получаю его счетчик сохранения, равный единице. Несмотря на то, что я выпустил burpAnim, я получил его счетчик сохранения, равный единице, из-за этого CCSpriteFrameCache не может удалить spriteFrames, и, следовательно, текстура также не удаляется.

Ваша первая проблема заключается в том, что вы звоните retainCount и думаете, что возвращаемый номер имеет смысл.

Счетчик сохранения объекта всегда следует рассматривать как дельту. Если вы увеличиваете его, сохраняя что-то, вы должны уменьшить его, высвобождая или автоматически высвобождая где-то еще. Где полностью зависит от того, как долго вы «владеете» ссылкой на объект.

Есть и другие сомнительные моменты:

    burpAnim = [[CCAnimation alloc] initWithFrames:burpFrames delay:0.04f];
    [burpFrames removeAllObjects];

Почему вы настраиваете содержимое burpFrames в цикле for() прямо перед этим, затем передаете его CCAnimation, а затем сразу же removeAllObjects? Если CCAnimation не копирует массив, значит, вы только что вычистили его из-под анимации. Поскольку массив автоматически освобождается, его не нужно очищать.

То же самое касается burpParticleFrames.

Взятие блокировки (dictLock) на поток и последующий вызов основного потока кажется сомнительным; как отличный способ создать мертвую блокировку. Если основной поток не должен блокировать этот поток, работает ли у вас более одного фонового потока? Какова ваша модель параллелизма?

Обратите внимание, что [self removeChild:characterSprite cleanup:YES];, скорее всего, выпустит characterSprite, поскольку, надеюсь, метод self будет следовать обычным соглашениям Cocoa.

Все это звучит так, будто у вас есть некоторые основные проблемы с сохранением/выпуском. Прочитайте руководство, а затем используйте Сборка и Проанализируйте, чтобы исправить любые проблемы. Если ваше приложение по-прежнему дает сбой, используйте обнаружение зомби, чтобы выяснить, какие сообщения отправляются после освобождения.

person bbum    schedule 15.01.2011
comment
Здесь нет проблем!!! проблема, с которой я столкнулся, заключалась в другом. Кстати, когда вы делаете CCAction и используете CCCallFunc и запускаете его на спрайте, скажем, X, то даже если вы удалите спрайт из слоя, вызвав removeChild, он не получит освобождения, пока выполнение не достигнет закрывающей скобки метода @selector. - person Asymptote; 17.01.2011
comment
Вы сказали, почему вы настраиваете содержимое burpFrames в цикле for() непосредственно перед этим, затем передаете его в CCAnimation, а затем сразу же удаляете все объекты? Если CCAnimation не копирует массив, значит, вы только что освободили его из-под анимации. Поскольку массив автоматически освобождается, его не нужно очищать. почему ccanimation не копирует я его инициализирую, с кодом проблем нет, был баг в cocos2d с загрузкой pvr.ccz. - person Asymptote; 18.01.2011
comment
Ваша первая проблема заключается в том, что вы вызываете continueCount и думаете, что возвращаемое число имеет смысл. Почему это не имеет смысла? прочитайте мой первый комментарий. - person Asymptote; 18.01.2011
comment
Найдите в StackOverflow слово «retainCount». Это почти бесполезный метод. Затем вы заполняете массив, отправляете его объекту, а затем очищаете, это очень странный, нестандартный шаблон. Это может сработать, но для тех, кто достаточно долго работает с Cocoa, это выглядит неправильно. Это действительно задокументированный правильный шаблон? (У меня нет с собой исходников cocos2d, иначе я бы поискал). - person bbum; 18.01.2011