Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 824
Warren Whipple Avatar asked Jun 25 '14 17:06

Warren Whipple


People also ask

Why We Use weak self in closure in Swift?

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.

What is the difference between weak self and unowned self?

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.

Do you need weak self in your closure?

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.

Why can not we just use weak everywhere and forget about unowned?

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.


2 Answers

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

like image 156
TenaciousJay Avatar answered Oct 19 '22 04:10

TenaciousJay


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

like image 25
user102008 Avatar answered Oct 19 '22 02:10

user102008