This SpriteKit action repeats by calling itself with a completion closure. It uses a closure, rather than an SKAction.repeatActionForever()
, because it needs to generate a random variable each repetition:
class Twinkler: SKSpriteNode {
init() {
super.init(texture:nil, color:UIColor.whiteColor(), size:CGSize(width:10.0, height:10.0))
twinkle()
}
func twinkle() {
let rand0to1 = CGFloat(arc4random()) / CGFloat(UINT32_MAX)
let action = SKAction.fadeAlphaTo(rand0to1, duration:0.1)
let closure = {self.twinkle()}
runAction(action, completion:closure)
}
}
I think I should be using [unowned self]
to avoid a strong reference cycle with the closure. When I do that:
let closure = {[unowned self] in self.twinkle()}
It crashes with the error: _swift_abortRetainUnowned
. But if I use [weak self]
instead:
let closure = {[weak self] in self!.twinkle()}
It executes without error. Why would [weak self]
work but [unowned self]
break? Should I even be using either of these here?
The Twinkler
object is strongly referenced elsewhere in the program, as a child of another node. So I don't understand how the [unowned self]
reference is breaking. It shouldn't be deallocated.
I tried replicating this problem outside SpriteKit using dispatch_after()
, but I was unable to.
In Swift, [weak self] prevents closures from causing memory leaks in your application. This is because when you use [weak self], you tell the compiler to create a weak reference to self. In other words, the ARC can release self from memory when necessary.
Use a weak reference whenever it is valid for that reference to become nil at some point during its lifetime. Conversely, use an unowned reference when you know that the reference will never be nil once it has been set during initialization. In general, be very careful when using unowned.
Using [weak self] is only required within situations in which capturing self strongly would end up causing a retain cycle, for example when self is being captured within a closure that's also ultimately retained by that same object.
Without using weak or unowned you're basically telling ARC that a certain “strong reference” is needed and you're preventing the reference count from going to zero. Without correctly using these keywords we possibly retain memory which can cause memory leaks in your app.
If self could be nil in the closure use [weak self].
If self will never be nil in the closure use [unowned self].
If it's crashing when you use [unowned self] then self is probably nil at some point in that closure so you would need to use [weak self] instead.
The examples from the documentation are pretty good for clarifying using strong, weak, and unowned in closures:
https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html
This sounds like a bug. {[unowned self] in self.twinkle()}
should work identically to {[weak self] in self!.twinkle()}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With