我为此感到羞耻,但是是的。即使我使用 ARC ,我也遇到了问题。
我的主要问题是:我的代码中有循环引用吗?
我的代码说明:
我有一个带有一系列子节点(背景、playerEntity、inputlayer)的游戏场景。问题是当我触发游戏并替换场景时,场景不会释放(我在游戏场景中添加了一个 dealloc 方法,即使我使用 ARC 不需要)。
我相信这是因为在子节点中我指的是游戏场景,而在游戏场景中我指的是它们,创建了一个循环引用。
例如,在游戏场景更新方法中,我调用以下内容:
-(void) update:(ccTime)delta
{
bool isGamePaused = [GameController sharedGameController].isGamePaused;
if(isGameOverInProgress==true){
//Do whatever game over animation u like
}
else if(isGamePaused==false)
{
elapsedTime+=delta;
//Update input layer
InputLayerButtons *inputLayer = (InputLayerButtons *) [self getChildByTag:InputLayerTag];
[inputLayer update:delta];
//Move background
ParallaxMultipleBackgroundOneBatchNode* background = (ParallaxMultipleBackgroundOneBatchNode*) [self getChildByTag:BackgroundNodeTag];
[background update:delta];
//verify enemies bullet collision
[self verifyPlayerBulletCollision];
[levelSprites update:delta];
//Update bullets position
[bulletCache updateVisibleBullets:delta];
我知道这是一种疯狂的方法,但我想避免在子节点中安排更新,以便在 ShooterScene 类中完全控制游戏中发生的事情。我没有对 ShooterScene 类使用半单例模式,而是有一个半单例 GameController 类实例,用于在节点之间传达游戏状态。
但是在某些子节点中,我不得不引用父 ShooterScene,因为例如使用半单例 GameController 类来存储船位置的响应速度太慢(例如,在更新方法中读取位置并相应地更新船证明要慢得多而不是像我在这里那样直接更新它)。因此,我的方法并不是像我希望的那样 100% 干净(我想避免对父类的所有引用,以避免循环引用的问题,并保持对 ShooterScene 类中所有事件的控制)。
因此,例如,这是我从输入层(即InputLayerButtons)更新船舶位置的方法:
-(void) update:(ccTime)delta
{
// Moving the ship with the thumbstick.
ShooterScene * shooterScene = (ShooterScene *) [self parent];
ShipEntity *ship = [shooterScene playerShip];
delta = delta * 2.0f;
CGPoint velocity = ccpMult(joystick.velocity, 200);
if (velocity.x != 0 && velocity.y != 0)
{
ship.position = CGPointMake(ship.position.x + velocity.x * delta, ship.position.y + velocity.y * delta);
}
}
我认为引用父场景是可以的,并且这不会导致循环引用。但它似乎发生了,所以我对此感到困惑。
这是游戏结束方法的代码,ShooterScene 的 dealloc 方法从未被调用(而是调用 cleanup):
[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:4.0 scene:[MainMenuScene scene] withColor:ccc3(255, 255, 255)]];
replaceScene 中有什么我不明白的地方吗?我找不到replaceObjectAtIndex的代码,所以在这里我只发布了 replaceScene 的 Cocos2d 2.0 代码
-(void) replaceScene: (CCScene*) scene
{
NSAssert( scene != nil, @"Argument must be non-nil");
NSUInteger index = [scenesStack_ count];
sendCleanupToScene_ = YES;
[scenesStack_ replaceObjectAtIndex:index-1 withObject:scene];
nextScene_ = scene; // nextScene_ is a weak ref
}
我试图查看是否会在其他场景中调用 dealloc 方法(比 ShooterScene 更简单,并且没有潜在的循环引用)并且它确实有效。所以我非常有信心这是由于循环引用,但我怎样才能检测到导致这种情况发生的代码呢?