iOS weak strong

grandM

macrumors 65816
Original poster
Oct 14, 2013
1,104
57
Hi guys

I'm going through a book on closures and I have a question about it.

Code:
extension Editor {
func editTutorial(_ tutorial: Tutorial) {

    queue.async() {

      [weak self] in

      guard let self = self else {

        print("I no longer exist so no feedback for you!")

        return

      }

      DispatchQueue.main.async {

        print(self.feedback(for: tutorial))

      }

    }
  }
}
This author tries to explain the need for using the weak keyword. Doing so he states '‘If self is not nil it will capture a strong reference and make sure it sticks around until the print statement finishes'.

I am a bit confused now. This code is used to make sure that the object still exists to perform the feedback, and hence the print. This would imply that self not being nil no longer becomes a weak self but a strong one through the guard statement.

If that to be the case then the closure now points strongly to the Editor object. The Editor object points strong to the closure. So how can the Editor object still be deallocated? Or is a closure deallocated the moment it reached the end of its statements? Because I thought this was not the case. Moreover the Editor object points strongly to it?

Thanks for your help. I'm hurting my head over this.
 

PhoneyDeveloper

macrumors 68040
Sep 2, 2008
3,114
93
Do you know what a retain cycle is? Declaring the closure to have a weak capture of self prevents a retain cycle. If self has been deinited already when the closure is executed then the closure simply exits.
 

grandM

macrumors 65816
Original poster
Oct 14, 2013
1,104
57
Do you know what a retain cycle is? Declaring the closure to have a weak capture of self prevents a retain cycle. If self has been deinited already when the closure is executed then the closure simply exits.
Yes I know what a retain cycle is. The weak keyword breaks the cycle. It is used so that if the instance is to be deallocated the self value in the closure no longer will prohibit self being deallocated.

However in this example the author first looks if self is not nil the moment the asynchronous method lifts off. If it is not nil the author wants to make sure that self is not deallocated until the feedback(for:) method has finished its task. So he uses the guard statement to create a new strong reference to self, although the assigned self was a weak reference.

This confuses me for two reasons
1 I did not know that a weak reference can be turned into a strong one using guard
2 If the closure at that moment has a strong reference to self, it seems self no longer can be deallocated because once more we have a retain cycle?

Or is a copy of self stored in the closure instead of a reference to self using the capture list? In that case self could be deallocated entering the closure because a copy of self would be present in the closure and not a pointer to the self object? But then that would be a call-by-value copy. In that case changes to self no longer would be taken into account executing the closure?
 

PhoneyDeveloper

macrumors 68040
Sep 2, 2008
3,114
93
This is apparently a swift 4.2 feature. That code wouldn't compile in older versions of swift, I believe. It was typically written like:

Code:
guard let strongSelf = self else { return }
strongSelf.doSomething()
but the use of strongSelf everywhere is also ugly. I think the meaning of the guard statement in your example is the same as in the strongSelf example. It just unwraps the variable. It doesn't do any other magic.

This is the proposal

https://github.com/apple/swift-evol...sals/0079-upgrade-self-from-weak-to-strong.md
 
Last edited:
  • Like
Reactions: grandM

grandM

macrumors 65816
Original poster
Oct 14, 2013
1,104
57
This is apparently a swift 4.2 feature. That code wouldn't compile in older versions of swift, I believe. It was typically written like:

Code:
guard let strongSelf = self else { return }
strongSelf.doSomething()
but the use of strongSelf everywhere is also ugly. I think the meaning of the guard statement in your example is the same as in the strongSelf example. It just unwraps the variable. It doesn't do any other magic.

This is the proposal

https://github.com/apple/swift-evol...sals/0079-upgrade-self-from-weak-to-strong.md
Superb link!

1 It does transform a weak reference into a strong one. So it does more than unwrapping. Or is weak an Optional wrapping a strong counterpart?
2 When all the statements in the closure are finished are the captured and other variables set to nil, free to be removed from memory?

Thanks once more
 

Mascots

macrumors 68000
Sep 5, 2009
1,608
1,303
Superb link!

1 It does transform a weak reference into a strong one. So it does more than unwrapping. Or is weak an Optional wrapping a strong counterpart?
2 When all the statements in the closure are finished are the captured and other variables set to nil, free to be removed from memory?

Thanks once more
When you unwrap any optional that represents a weak reference, you are given a strong reference and the reference count is increased - the weak reference itself is still available and is not modified. You are asking if the object is available and then provided strong reference as a promise by the system that the object will be kept around since you are accessing it in a way which a deallocation would cause a crash that could never be anticipated or caught.

This strong reference is, however, temporary. Because it was created within the closure and not captured by the closure, the reference count will be decremented when the scope is completed.
 
  • Like
Reactions: grandM

grandM

macrumors 65816
Original poster
Oct 14, 2013
1,104
57
When you unwrap any optional that represents a weak reference, you are given a strong reference and the reference count is increased - the weak reference itself is still available and is not modified. You are asking if the object is available and then provided strong reference as a promise by the system that the object will be kept around since you are accessing it in a way which a deallocation would cause a crash that could never be anticipated or caught.

This strong reference is, however, temporary. Because it was created within the closure and not captured by the closure, the reference count will be decremented when the scope is completed.
1 Do I understand you correctly that the weak self is always an Optional? If so is an unowned self an implicitly unwrapped Optional?

2 The async defines a closure. Does this closure stick around indefinitely or is it removed once the function ends its statements?

3 This out of scope thing always confuses me. Is this the same as stating that the statements of the closure are all executed and you leave the closure. Hence the variables of the closure are no longer needed and can be removed from memory when iOS needs the memory? This would of course imply that the async closure ceases to exist having executed all its statements?

4 I get the impression you imply that the closure sticks around because you refer to the capture list capturing that weak reference to self. In that case it seems a bit strange that the strong reference would be removed?

Thanks for your answer.
 

PhoneyDeveloper

macrumors 68040
Sep 2, 2008
3,114
93
1 Do I understand you correctly that the weak self is always an Optional? If so is an unowned self an implicitly unwrapped Optional?
Yes. Yes.

2 The async defines a closure. Does this closure stick around indefinitely or is it removed once the function ends its statements?
It's up to the semantics of the queue.async method to decide the lifetime of the closure. For something like DispatchQueue.main.async the lifetime is one execution of the closure.

3 This out of scope thing always confuses me. Is this the same as stating that the statements of the closure are all executed and you leave the closure. Hence the variables of the closure are no longer needed and can be removed from memory when iOS needs the memory? This would of course imply that the async closure ceases to exist having executed all its statements?
It's not really different than any function scope. The function executes. Then it's done. No traces of it remain. A retain cycle can change that.

4 I get the impression you imply that the closure sticks around because you refer to the capture list capturing that weak reference to self. In that case it seems a bit strange that the strong reference would be removed?
Again, only for the life of the closure.

Thanks for your answer.
 
  • Like
Reactions: Mascots and grandM
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.