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:创buildUIImages,然后通过调用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; }