Peter Senyszyn Peter Senyszyn - 4 months ago 29
iOS Question

How to properly deallocate a Set of objects that inherit from SKSpriteNode

I'm wondering what the best way to deallocate the objects of a Set that inherit from SKSpriteNode. I have the following code:

class Raindrop : SKSpriteNode
{
weak var barSpriteRef: SKSpriteNode?

init(scene: SKScene, barSprite: SKSpriteNode)
{
let texture = SKTexture(imageNamed: "RainDrop")

super.init(texture: texture, color: SKColor.whiteColor(), size: texture.size())

barSpriteRef = barSprite

self.userInteractionEnabled = true

let width = scene.view!.frame.width

let randomPos = CGPointMake(CGFloat(arc4random()) % width, UIScreen.mainScreen().bounds.height + 50)

self.position = randomPos
self.zPosition = 1
self.anchorPoint = CGPoint(x: 0.5, y: 0.5)

scene.addChild(self)

let moveDown = SKAction.moveToY(-UIScreen.mainScreen().bounds.height, duration: 8)
self.runAction(moveDown)
}

required init?(coder aDecoder: NSCoder)
{
fatalError("init(coder:) has not been implemented")
}

func kill()
{
self.removeAllActions()
self.removeFromParent()
}
}


The function kill() is my attempt at deallocating, but it's not working as intended.

And I'm using a Set like so:

var raindrops = Set<Raindrop>()

Answer

How ARC does work

ARC does keep in memory the objects that are strongly referenced.

SpriteKit

This is also true in SpriteKit infact every node strongly referenced by the GameScene (or referenced by a node reference by the GameScene...) is kept in memory.

What your are doing is correct (but probably not enough)

You are trying to deallocate your Raindrop sprite using your kill method

func kill() {
    self.removeAllActions()
    self.removeFromParent()
}

This method does work if the current Raindrop is referenced only by it's parent and by some actions.

However if into another node you created a this Set

var raindrops = Set<Raindrop>()

and then added your sprite to the Set, you created another strong reference which will keep your Raindrop sprite in memory.

Example

Let's define a GameScene and a Hero node.

class GameScene: SKScene {
    deinit { print("GameScene has been deallocated") }
}

class Hero: SKNode {
    deinit { print("Hero has been deallocated") }
}

The deinit will print a message into the console as soon as the object is deallocated

Now let's look a this code

let scene = GameScene(size: CGSize(width: 100, height: 100))
var hero: SKNode? = Hero()
var set = Set<SKNode>([hero!])
scene.addChild(Hero())

There are 3 strong references do the Hero object

  1. from the scene
  2. the hero variable
  3. the set variable

Let's remove the first 2 references

hero?.removeFromParent()
hero = nil

Hero is still in memory because strongly reference by set.

Finally let's run

set.removeAll()

now we get the following message because Hero has finally been deallocated.

Hero has been deallocated
Comments