iOS 7 Sprite Kit释放内存

我正在构build一个针对新的iOS 7和Sprite Kit的iOS游戏,使用发射器节点和物理来增强游戏性。 在开发应用程序的时候,我遇到了一个严重的问题:创build你的场景,节点,效果,但是当你完成并且需要返回到主屏幕时,你如何释放这些资源分配的所有内存?

理想情况下,ARC应该释放一切,应用程序应该回到创build场景之前的内存消耗级别,但这不是发生的情况。

我添加了下面的代码,作为视图的dealloc方法,它绘制场景并负责在closures(删除)时删除所有内容:

- (void) dealloc { if (scene != nil) { [scene setPaused:YES]; [scene removeAllActions]; [scene removeAllChildren]; scene = nil; [((SKView *)sceneView) presentScene:nil]; sceneView = nil; } } 
  • sceneView是一个UIView,它是场景的容器
  • 场景是SKScene类的扩展,创build所有SKSpriteNode对象

我非常感谢在这个问题上的任何帮助。

我有很多Sprite Kit的内存问题,我用技术支持票来获取信息,这可能与此有关。 我问是否开始一个新的SKScene将完全释放前一个使用的所有内存。 我发现这个:

当切换到新的SKScene时,由+ textureWithImageNamed分配的底层内存可能会(也可能不会)(通常不会)被释放。 你不能依靠那个。 iOS释放由+ textureWithImageNamed:或+ imageNamedcaching的内存:当它看起来合适时,例如当它检测到低内存条件时。

如果您想要在纹理完成后立即释放内存,则必须避免使用+ textureWithImageNamed:/ + imageNamed :. 创buildSKTextures的另一种方法是:首先用+ imageWithContentsOfFile:创buildUIImage,然后通过调用SKTexture / + textureWithImage(UIImage *)从结果UIImage对象创buildSKTextures。

我不知道这是否有帮助。

所有这些代码是多余的。 假如你的代码没有内存泄漏或保留周期,一旦你释放Sprite Kit视图,所有内容都将被清除。

在引擎盖下,Sprite Kit使用了一个caching机制,但是我们没有办法控制它,如果它被正确地实现(这是安全的),我们也不需要。

如果这不是你在仪器上看到的,检查保留周期,泄漏。 validation场景和视图的dealloc是否被调用。 确保没有强大的引用视图,场景或其他节点保留在其他对象(特别是单身人士和全局variables)。

打了几天后,关键是:[sceneView presentScene:nil]; 或者对于Swift:sceneView.presentScene(nil)

这可以在viewDidDisappear中完成。 没有这个,即使被解雇,你的观点仍然会留在亲爱的生活场景中,并继续咀嚼记忆。

Swift 3

在我个人的经验中,我已经在Xcode仪器的帮助下解决了问题,首先是活动监视器显示了我内存的大量增加,而不是分配和泄漏。

但是也有一个有用的方法,就是debugging控制台

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

这是另一个帮助,看看是否每次你想删除一个场景调用deinit

如果你有任何人,你必须把它变成弱的,例如:

 weak var parentScene:SKScene? 

同样的事情协议,你可以声明它像这个例子使用属性class弱:

 protocol ResumeBtnSelectorDelegate: class { func didPressResumeBtn(resumeBtn:SKSpriteNode) } weak var resumeBtnDelegate:ResumeBtnSelectorDelegate? 

ARC 做所有我们需要的工作,但是,如果你认为你已经忘记了正确的写一些属性(initiliazation,blocks ..),我也使用了一些类似于我的debugging阶段的函数:

 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() } 

我有一个类似的问题,像你@ 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被声明为强:

 @property (nonatomic,strong) WBMMiniGameVCTemplate *parentVC; 

解决scheme1:

并将其更改为:

 @property (nonatomic,weak) WBMMiniGameVCTemplate *parentVC; 

为我解决了这个问题。

说明:对于作为UIViewController的父VC( myViewController )的引用已被存储在某处。 由于这个VC对SKScene有很强的参考,所以和它一起存储。 我甚至从这个SKScene的控制台输出,如它仍然活跃。 关于为什么发生在我身上的最好的一点是我有最强的指针。

解决scheme2:

在我的myViewController下:

 - (void)viewDidDisappear:(BOOL)animated 

我打了电话 :

 self.ballonMGScene.parentVC = nil; 

在离开当前的VC( myViewController )时,我将指针设置为nil,除去内存以及所有内容。

这两个解决scheme为我工作。 我用debugging器对它进行了testing。 内存消耗正常上升和下降。

希望这有助于理解问题和解决scheme。

尝试在删除场景之前保留sceneView。

 -(void)dealloc { [sceneView presentScene:nil]; [sceneView release]; [super dealloc]; } 

它采取了一些步骤,但我完全解决了我的问题:

1)在My ViewControl中,我创build了一个方法来强制销毁所有的孩子:

 -(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)由于我在场景中创build了一个强大的协议,并在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; }