0

I have a Swift code like this:

  private var myVar = 0 {
    didSet {
        DispatchQueue.main.async { [weak self] in

            if let myVar = self?.myVar {
                if myVar > 0 {
                   // Do some UI stuff, access myVar again
                }        
            }
        }
    }
}

My question is do we always have to go through the pain 'if let myVar = self?.myVar' and then check myVar, specifically here where we are in didSet block of the same variable?

Deepak Sharma
  • 5,577
  • 7
  • 55
  • 131
  • Why are you dispatching async to the main queue? if your switching threads and using weak self then you will need to unwrap self – Scriptable Jan 10 '19 at 15:08
  • `if (self?.myVar ?? 0) > 0 { }` maybe? The issue is about the `weak self` which is optional, maybe you want the `guard let self = self else { return }` instead? Why main queue? – Larme Jan 10 '19 at 15:09
  • That was an example, I need to change UI depending on myVar and therefore mainQueue. – Deepak Sharma Jan 10 '19 at 15:11
  • 1
    GCD closures don't cause retain cycles, period.`[weak self]` is pointless. – vadian Jan 10 '19 at 15:25

1 Answers1

3

DispatchQueue.main.async is guaranteed to execute the provided closure and it will not store reference to the passed closure, thus will not cause memory leak even if you don't mark self as weak. So, following should be safe enough:

private var myVar = 0 {
  didSet {
    DispatchQueue.main.async {
      if self.myVar > 0 {

      }        
    }
  }
}

Note that, even if your reference to the object becomes zero, a reference to self will still exist until the async closure is disposed. So self will live until the async block is executed and disposed by DispatchQueue

Orkhan Alikhanov
  • 9,122
  • 3
  • 39
  • 60
  • That's interesting, but what has guarantee of execution got to do with storing reference to closure. Please explain. – Deepak Sharma Jan 10 '19 at 15:15
  • In other words, when do we need weak self and when can we access directly in closure. How do we know if closure will retain variable or not. – Deepak Sharma Jan 10 '19 at 15:17
  • In the case you don't pass `self` as `weak` (or `unowned`) into the closure, the closure will hold reference to it. Once `DispatchQueue` executes the closure it removes reference to the closure, and as soon as reference count to the closure gets zero, it will be disposed. When it's disposed the reference count to `self` will also be decreased by one. Since the closure does not exist anymore – Orkhan Alikhanov Jan 10 '19 at 15:19
  • What I mean by `guarantee of execution` is that, it won't store reference to the closure once it executes it. – Orkhan Alikhanov Jan 10 '19 at 15:21
  • `when do we need weak self and when can we access directly in closure` This question might require a lecture. In short, to avoid reference cycles. If the passed closure will be stored in `an object` that's stored in `self`, you'll get reference cycle, hence memory leak. – Orkhan Alikhanov Jan 10 '19 at 15:26
  • Ok it looks exactly like Objective-C then. As I read, GCD blocks do not require weak references but other closures do. What I am trying to understand is difference between two scenarios. – Deepak Sharma Jan 10 '19 at 17:37
  • Yes, GCD is implemented in c and works both in ObjC and Swift. Even can run in linux, swift allows that. – Orkhan Alikhanov Jan 10 '19 at 17:48
  • `GCD blocks do not require weak references but other closures do` Well, GCD does not get any special treatment here, [`UIView.animate(withDuration:animations:)`](https://developer.apple.com/documentation/uikit/uiview/1622418-animate) does not require weak as well. It's a matter of whether the closure is stored or not, and how it it's stored. See [this thread](https://stackoverflow.com/q/24320347) – Orkhan Alikhanov Jan 10 '19 at 17:50