Выделение объекта авто-релиза в начале? - PullRequest
1 голос
/ 16 октября 2011

У меня есть класс с именем GamePlay , который выглядит примерно так:

@implementation GamePlay
-(id)init{
    if((self = [super init])){
        self.isAccelerometerEnabled = YES;

        //ship defined in header
        ship = [Ship shipWithParentNode:self];
        CGSize screenSize = [[CCDirector sharedDirector] winSize];
        float imageHeight = [ship spriteContentSize].height;
        [ship setSpritePosition:CGPointMake(screenSize.width*0.5, imageHeight*0.5)];
    }
    return self;
}

-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration{
    CGPoint pos = [ship spritePosition];
    pos.x = acceleration.x * 10;
    [ship setSpritePosition:pos];
}
@end

Итак, класс Ship выглядит примерно так:

@implementation Ship

+(id)shipWithParentNode:(CCNode *)parentNode{
    return [[[Ship alloc] initWithParentNode:parentNode] autorelease];
}

-(id)initWithParentNode:(CCNode *)parentNode{
    if((self = [super init])){
        sprite = [CCSprite spriteWithFile:@"ship.png"];
        SpriteLoader *spriteLoader = [SpriteLoader sharedSpriteLoader];
        [spriteLoader addTextureAtlas:@"Spites_default.plist"];
        CCAnimation *spriteAnimation = [CCAnimation animationWithFrames:[spriteLoader getSpriteFramesWithName:@"ship-" andAmount:[NSNumber numberWithInt:5]] delay:0.08f];
        CCAnimate *anim = [CCAnimate actionWithAnimation:spriteAnimation];
        CCRepeatForever *repeat = [CCRepeatForever actionWithAction:anim];
        [sprite runAction:repeat];
        [parentNode addChild:sprite z:0 tag:SHIP];
    }
    return self;
}

-(void)setSpritePosition:(CGPoint)point{
    sprite.position = point;
}

-(CGPoint)spritePosition{
    return sprite.position;
}

-(CGSize)spriteContentSize{
    return sprite.contentSize;
}
@end

GamePlay инициализирует штраф Ship и продолжает модифицировать CCSprite в пределах Ship , и в симуляторе все хорошо.Когда дело доходит до запуска его на устройстве, мы получаем ввод акселерометра.В методе акселерометра первая строка потерпела крах программы, потому что корабль больше не существует.Если я смотрю в отладчике с точкой останова в первой строке метода акселерометра, я вижу следующее: self = (GamePlay *)-> ship = (Ship *) 0x004701e0

Если я продолжу выполнение программы, я получу это сообщение: сообщение отправлено на освобожденный экземпляр 0x4701e0

Но я не уверен, почему этобыл освобожден ... И предположительно 0x004701e0 == 0x4701e0?

Большое спасибо, Бен

Ответы [ 2 ]

4 голосов
/ 16 октября 2011

Вы должны retain ship в -[GamePlay init] (и позже release в dealloc, конечно).

3 голосов
/ 16 октября 2011

Для объяснения проблемы:

  • Класс GamePlay инициализирует экземпляр класса Ship как автоматическое освобождение
  • Класс Ship инициализирует класс спрайта и добавляет его в качестве дочернего к parentNode (класс GamePlay), которыйсохраняет спрайт, но не сам класс Корабля

Оле верно, что Корабль нуждается в сохранении в коде, который вы опубликовали.Лично я вижу здесь проблему с дизайном.Ваш класс Ship должен быть производным от CCNode, и вы должны добавить Ship в иерархию узлов с помощью addChild.

Если Ship происходит только из NSObject, то, что вы в итоге получите, похоже на «сломанную» иерархию узлов:

  • Класс Cocos2D GamePlay (то есть CCLayer)
  • NSObject Класс корабля
  • Экземпляр Cocos2D CCSprite содержится в классе Ship, но добавлен в класс GamePlay

Проблема в том, что спрайт класса «Корабль» «управляется» классом «Корабль», но сохраняется классом GamePlay.Это означает, что вы несете ответственность за сохранение классов не-CCNode, таких как Ship самостоятельно.Следующее делает более простой и более соответствующий Cocos2D дизайн, потому что он опирается на Cocos2D, управляющий всей иерархией узлов:

  • Cocos2D GamePlay класс (т.е. CCLayer)
  • Cocos2D Ship class (производныйиз CCNode)
  • Экземпляр Cocos2D CCSprite, содержащийся в классе Ship, добавленный в класс Ship как дочерний

Таким образом, вы добавите класс Ship в качестве дочернего в класс GamePlay.Класс Ship добавляет свой экземпляр CCSprite к себе (класс Ship).Вы можете (и должны) избавиться от parentObject, переданного в методе shipWithParentNode.В Cocos2D довольно опасно передавать экземпляр узла другому узлу, у вас может возникнуть соблазн сохранить его, что может привести к утечке всей сцены из-за циклических зависимостей сохранения (a сохраняет b, b сохраняет a, оба могут 't go go).

В целом, это делает вашу иерархию узлов немного глубже, но управлять ею намного проще.Вы можете предположить, что все объекты являются производными от общего базового класса (CCNode), и вы можете рассчитывать на то, что Cocos2D освободит иерархию узлов в правильном порядке в нужное время.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...