20

新しい iOS 7 とスプライト キットを対象とした iOS ゲームを作成しています。エミッタ ノードと物理演算を使用してゲームプレイを強化しています。アプリの開発中に深刻な問題に遭遇しました。シーン、ノード、エフェクトを作成しますが、完了してメイン画面に戻る必要がある場合、これらのリソースによって割り当てられたすべてのメモリをどのように解放しますか?

理想的には、ARC がすべてを解放し、アプリケーションがシーンを作成する前のメモリ消費レベルに戻る必要がありますが、実際にはそうなっていません。

ビューの dealloc メソッドとして次のコードを追加しました。これは、シーンを描画し、閉じた (削除された) ときにすべてを削除する責任があります。

- (void) dealloc
{
    if (scene != nil)
    {
        [scene setPaused:YES];

        [scene removeAllActions];
        [scene removeAllChildren];

        scene = nil;

        [((SKView *)sceneView) presentScene:nil];

        sceneView = nil;
    }
}
  • sceneView はシーンのコンテナである UIView です。
  • シーンは SKScene クラスの拡張であり、すべての SKSpriteNode オブジェクトを作成します

この問題について何か助けていただければ幸いです。

4

7 に答える 7

19

スプライト キットで多くのメモリの問題が発生し、技術サポート チケットを使用して情報を取得しました。ここに関連する可能性があります。新しい SKScene を開始すると、前の SKScene で使用されていたすべてのメモリが完全に解放されるかどうかを尋ねていました。私はこれを見つけました:

+textureWithImageNamed: によって割り当てられた基になるメモリは、新しい SKScene に切り替えるときに解放される場合と解放されない場合があります (通常は解放されません)。それに頼ることはできません。iOS は、+textureWithImageNamed: または +imageNamed: によってキャッシュされたメモリを解放します。たとえば、メモリ不足の状態が検出された場合などです。

テクスチャの処理が完了したらすぐにメモリを解放したい場合は、+textureWithImageNamed:/+imageNamed: の使用を避ける必要があります。SKTexture を作成する代わりに、最初に +imageWithContentsOfFile: を使用して UIImage を作成し、次に SKTexture/+textureWithImage:(UIImage*) を呼び出して、結果の UIImage オブジェクトから SKTexture を作成します。

これがここで役立つかどうかはわかりません。

于 2014-02-04T02:19:53.493 に答える
5

スウィフト 3 :

私の個人的な経験では、Xcode インストゥルメントの助けを借りて解決しました。まず、割り当てとリークよりもメモリの大幅な増加をすぐに示したアクティビティ モニターを使用しました。

しかし、便利な方法もあります。

deinit {
       print("\n THE SCENE \(type(of:self)) WAS REMOVED FROM MEMORY (DEINIT) \n")
}

これはdeinit、シーンを削除するたびに が呼び出されたかどうかを確認するのに役立ちます。

sceneクラスにまたはへの強い参照はありませんparent。誰かがいる場合は、次のように弱いものに変換する必要があります。

weak var parentScene:SKScene?

プロトコルについても同じことが言えます。プロパティを使用して、この例のように弱いと宣言できますclass

protocol ResumeBtnSelectorDelegate: class {
    func didPressResumeBtn(resumeBtn:SKSpriteNode)
}

weak var resumeBtnDelegate:ResumeBtnSelectorDelegate?

ARC は必要なすべての作業を行いますが、いくつかのプロパティ(初期化、ブロックなど)を正しく書き忘れたと思われる場合は、デバッグフェーズで次のような関数も使用しました:

func cleanScene() {
    if let s = self.view?.scene {
        NotificationCenter.default.removeObserver(self)
        self.children
            .forEach {
                $0.removeAllActions()
                $0.removeAllChildren()
                $0.removeFromParent()
        }
        s.removeAllActions()
        s.removeAllChildren()
        s.removeFromParent()
    }
}

override func willMove(from view: SKView) {
    cleanScene()
    self.removeAllActions()
    self.removeAllChildren()
}
于 2016-09-03T11:32:20.397 に答える
1

@ user2857148のような同様の問題がありました。私は VC に次のものを提示します。

[self presentViewController:myViewController animated:YES completion:nil];

私が持って@implementation myViewControllerいた:

- (void)viewDidLayoutSubviews
{
    // Configure the view.
    SKView * skView = (SKView *)self.view;
    skView.showsFPS = YES;
    skView.showsNodeCount = YES;
    self.ballonMGScene = [[MBDBallonMiniGame alloc] initWithSize:skView.bounds.size andBallonImageNames:self.ballonObjectsArray];
    self.ballonMGScene.parentVC = self;
    self.ballonMGScene.scaleMode = SKSceneScaleModeAspectFill;
    self.ballonMGScene.physicsWorld.gravity = CGVectorMake(0, 0);
    // Present the scene.
    [skView presentScene:self.ballonMGScene];
} 

問題は次の場所にありました。

self.ballonMGScene.parentVC = self;

以降 :

@interface MBDBallonMiniGame : SKScene <SKPhysicsContactDelegate>

parentVC は strong で宣言されました:

@property (nonatomic,strong) WBMMiniGameVCTemplate *parentVC;

解決策 1:

そしてそれを次のように変更します:

@property (nonatomic,weak) WBMMiniGameVCTemplate *parentVC;

私のために問題を解決しました。

説明: 親 VC ( myViewController)への参照UIViewControllerがどこかに保管されています。この VC は SKScene への強い参照を持っていたため、一緒に保存されました。この SKScene がまだアクティブであるかのように、この SKScene からのコンソール出力さえありました。なぜこれが私に起こったのかについての私の最高の質問は、私が最も強力な指針を持っているということでした.

解決策 2:

私のmyViewController中で:

- (void)viewDidDisappear:(BOOL)animated

私は呼びました :

self.ballonMGScene.parentVC = nil;

現在の VC ( ) を離れるときmyViewControllerに、ポインタを nil に設定し、メモリとそれに付随するすべてのものを削除しました。

これらの2つのソリューションは私にとってはうまくいきました。デバッガーでテストしました。メモリ消費は正しく上下しました。

これが問題と解決策を理解するのに役立つことを願っています。

于 2014-04-29T11:56:42.253 に答える
0

いくつかの手順が必要でしたが、問題を完全に解決しました:

1) My ViewControl で、すべての子を強制的に破棄するメソッドを作成しました:

-(void)destroyAllSub:(SKNode*)node
{
    if(node == nil) return;
    if(![node isKindOfClass:[SKNode class]]) return;

    [node removeAllActions];
    for (SKNode *subNode in node.children) {
        [self destroyAllSub:subNode];
    }
    [node removeAllChildren];
}

2) シーンで強力なプロトコルを作成し、それを ViewControl で参照し、シーンも強力だったので、次のようにすべての参照を破棄しました。

[self.mainScene.view presentScene:nil]; //mainScene: the name of the Scene pointer
self.mainScene.myProt = nil; //myProt: The name of the strong protocol

@autoreleasepool {
    [self destroyAllSub:self.mainScene];
    self.mainScene = nil;
}
于 2015-11-16T01:28:52.717 に答える
0

シーンを削除する前に、シーン ビューを保持するようにしてください。

-(void)dealloc
{
[sceneView presentScene:nil];
[sceneView release];
[super dealloc];
}
于 2014-10-10T16:13:32.060 に答える