Warren Whipple Warren Whipple - 5 months ago 44
Swift Question

Why does [weak self] work but [unowned self] break in a Swift closure?

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.

Answer

This sounds like a bug. {[unowned self] in self.twinkle()} should work identically to {[weak self] in self!.twinkle()}