これは恥ずべきことですが、そうです。ARCを使用していても、これに問題があります。
私の主な質問は次のとおりです。コードに循環参照がありますか?
私のコードの説明:
一連の子ノード(background、playerEntity、inputlayer)を持つゲームシーンがあります。問題は、ゲームオーバーをトリガーしてシーンを置き換えると、シーンの割り当てが解除されないことです(ARCを使用しているため、必要がない場合でも、ゲームシーンにdeallocメソッドを追加しました)。
これは、子ノードではゲームシーンを参照し、ゲームシーンではそれらを参照して循環参照を作成しているためだと思います。
たとえば、ゲームシーンの更新メソッドでは、次のように呼び出します。
-(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クラスを使用して船の位置を保存すると、応答が遅すぎることが判明しました(たとえば、updateメソッドで位置を読み取り、それに応じて船を更新すると、はるかに遅くなります。ここで行うように直接更新するよりも)。したがって、私のアプローチは、私が望んでいたように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メソッドは呼び出されません(代わりにクリーンアップが呼び出されます)。
[[CCDirector sharedDirector] replaceScene:[CCTransitionFade transitionWithDuration:4.0 scene:[MainMenuScene scene] withColor:ccc3(255, 255, 255)]];
replaceSceneに私が理解できない何かがありますか?replaceObjectAtIndexのコードが見つからなかったので、ここでは、replaceSceneのCocos2d2.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
}
他のシーン(ShooterSceneよりも単純で、潜在的な循環参照がない)でdeallocメソッドが呼び出されるかどうかを確認しようとしましたが、機能しました。循環参照によるものだと確信していますが、これを引き起こすコードをどのように検出できますか?