0

Lets examine the following example

SomeLib.someAsyncFunction { [weak someVariable] in
   if let someVariableU = someVariable {
      // now someVariableU is unwrapped and strong reference created , we can use it as regular
   }
}

I assume that optional binding has a low level implementation similar(not exactly of course) to something like this

if variable != nil {
   return variable!
}

So, my question - is it possible that the object referenced by weak reference will deallocated during optional binding, I mean the last strong reference to the object is "cleared". If so what will happen in this case?

What will happen if the "nil check will pass" and then it will be deallocated, what will happen to "force unwrap"(I used parentheses because I understand that it's not exactly how it works)!

So, can somebody explain if this situation is even possible, and is o than what will happen?

Cristik
  • 30,989
  • 25
  • 91
  • 127
starwarrior8809
  • 361
  • 1
  • 10

2 Answers2

2

This entire structure, which dates back way into the Objective-C days, is traditionally called the "weak–strong dance". Let me explain the purpose of the dance.

Our overall purpose is: avoid the danger of a retain cycle and memory leak. That is why we say weak somevariable.

Having done that, however, we do indeed introduce the danger that the object pointed to by somevariable might be deallocated. However, we deal coherently with that danger, by saying if let. Here's how:

  • The object might have been deallocated by the time we enter the first curly braces in your code. But that's not a problem. The if let means that if the object has been deallocated, then in that case we get nil and we do nothing (we never enter the second curly braces).

  • If the object has not been deallocated by the first curly braces, then the if let succeeds, and then, as Cristik says, the if let creates a strong reference and now we enter the second curly braces with a guarantee that the object will persist for their entirety.

Thus, we get coherent and consistent behavior.

SomeLib.someAsyncFunction { // someVariable might be deallocated...
   [weak someVariable] in // ...and that is the point of `weak`, to allow that
   if let someVariableU = someVariable { // find out whether someVariable was deallocated
      // if we get here, someVariable was _not_ deallocated...
      // and someVariableU is a strong reference and persists thru this block
   }
}
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • Thank you for you answer! It explains a lot things ! So, basically to clarify - I was wondering if weakly referenced object can be deallocated during `if/guard let` statement itself. I mean if let statement(internal implementation) have to check first is the variable indeed has the value(not deallocated) and only then unwrap it. I mean can deallocation happen in between those steps? Or it is made with some kind of an "atomic" operation that does all this steps in a single operation ? – starwarrior8809 Nov 26 '20 at 19:47
  • Yes, the instant of saying `if let` is atomic. I understand that you are thinking it is two steps: (1) Is this thing still around? (2) If so, unwrap it. But it isn't two steps, at least not in the sense that something could happen between 1 and 2. – matt Nov 26 '20 at 19:50
  • To put it another way, if `if let` were not atomic, the entire universe would have exploded by now. But it hasn't. :) – matt Nov 26 '20 at 19:52
  • Basically you're asking how the magic of ARC weak works under the hood. The answer is that as long as the weak references to an object have not been manually zeroed out by the bookkeeping system, the object has one extra retain count, exactly so that things like `if let` can behave correctly. Conversely, when all the strong references all go away, the weak references _are_ manually zeroed out _and_ that extra retain count is decremented — and the object vanishes. – matt Nov 26 '20 at 20:08
  • Actually I guess it is how it was working until up to Swift 4. Object was retained until all it's weak refs were zeroed-out. Since Swift 4 objs do not store weak ref count as well as ref themself directly in the obj ! So, basically the obj was "living" until all weak refs that are pointing to it were manually zeroed-out. – starwarrior8809 Nov 26 '20 at 21:06
  • As far as I know since Swift4 obj is referenced by the side table that stores weak ref count as well as "refs" themself and also it has the refs to the object itself.And when you try to access the object through the weak ref you actually not referencing the object directly,but referencing the side table! So when strong ref count reaches zero the object gets vanished and the side tables ref to the object is cleared. So,basically I I got you correctly then you last comment is valid for Swift versions up until 3.Or I missed your point?sry for writing in two comments,tex is too long – starwarrior8809 Nov 26 '20 at 21:07
  • Yeah, I don't _really_ know. I was just guessing based on the discussion here: https://stackoverflow.com/a/65015629/341994 But the point is that they've clearly devised weak references exactly so that this kind of thing _does_ work, since, as I said, the universe would have exploded by now if it didn't. – matt Nov 26 '20 at 21:09
  • here is an interesting post regarding this https://www.hackingwithswift.com/articles/19/how-weak-references-work-in-swift-4 – starwarrior8809 Nov 26 '20 at 21:10
1

No, the object won't be deallocated during the execution of the optional binding block.

if let someVariableU = someVariable creates a strong reference, thus as long as that strong reference will be alive, so will the object it points to.

Cristik
  • 30,989
  • 25
  • 91
  • 127