3

This is not pure curiosity, there is a feeling that I may misunderstand something about weak references in Swift.

Suppose I create a class from a View Controller and pass its reference to the initialiser:

class = MyClass(vc: self)

Since the storyboard and window already keep a reference to this View Controller, it seems logical for MyClass to have a weak reference to it (for the similar reason all references created within IB are weak by default):

class MyClass: NSObject {
    private weak var viewController: UIViewController

    init(vc: UIViewController) {
       self.viewController = vc
       super.init
    }

    func setViewController(_ vc: UIViewController) {
       self.viewController = vc
    }

    ...
}

However this code gives compilation error, as viewController variable isn't optional. So I had to add '!' to viewController declaration and remove the initialiser, leaving only setViewController which looks rather unnatural.

What is the reason behind disallowing non-optional weak data?

pacification
  • 5,838
  • 4
  • 29
  • 51
cyanide
  • 3,885
  • 3
  • 25
  • 33
  • 1
    1) "Since the storyboard and window already keep a reference to this View Controller, it seems logical for MyClass to have a weak reference to it" Nope, this is not a good reason. You should use a weak reference if your object doesn't have an owning relationship over the vc, in order to block retain cycles. 2) "for the similar reason all references created within IB are weak by default" simply using a strong reference is preferred these days. 3) What would you expect to happen when you reference `viewController`, when the strong references to it expire? – Alexander Sep 08 '18 at 03:52
  • Alexander: 1) 'You should use a weak reference if your object doesn't have an owning relationship over the vc'. Indeed, MyClass doesn't own the VC; it's the storyboard who owns it. Therefore weak reference should be right – cyanide Sep 08 '18 at 04:00
  • Alexander: 2) If strong reference is preferred, why IB takes weak references by default? Pure nostalgia to old days? :) As you've mentioned, weak references help to block retained cycles. Modern Java doesn't use reference counts, so it doesn't offer weak references. On the contrary, Swift uses reference counts, so weak references are needed sometimes. – cyanide Sep 08 '18 at 04:07
  • Alexander 3) Can you please explain the meaning of 'strong reference is to expire'? – cyanide Sep 08 '18 at 04:08
  • 1) By your reasoning, only 1 strong reference should ever exist to an object. That's simply not the case. If you need a guaranteed life time of an object, you use a strong reference. – Alexander Sep 08 '18 at 04:50
  • 2) Pretty much just nostalgia, yep. [The current recommendation is to make them strong](https://stackoverflow.com/a/31395938/3141234) Weak references are sometimes necessary, yes, but you haven't stated that this is such a case. – Alexander Sep 08 '18 at 04:51
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/179666/discussion-between-alexander-and-cyanide). – Alexander Sep 08 '18 at 04:51
  • “it's the storyboard who owns it”—no, it doesn't. The `UIStoryboard` deserializes a new instance of the VC and then relinquishes ownership of it. The window owns it, if it is the window's `contentViewController`. Your object can *also* own it, if appropriate. – rob mayoff Sep 08 '18 at 05:12
  • rob mayoff. About the ownership, I agree. Storyboard just instantiates the VC, Once VC is presented, either window (for a root VC), or parent controller (for a child VC) get ownership of it. How the object can own itself? Won't it be a dead lock? – cyanide Sep 08 '18 at 05:19
  • “How can the object own itself”… well, it can keep a strong reference to itself. But that's not what you want here. It seems like either you want the VC to own the object, or you want the object to own the VC. If you want the VC to own the object, and want the object to have a reference to the VC, then to avoid a retain cycle, the object's reference must be either `weak` or `unowned`. If it's `weak`, it must be `Optional`. If it's `unowned`, it cannot be `Optional`. – rob mayoff Sep 08 '18 at 05:45

1 Answers1

11

The very definition of a weak variable is that the variable does not increase the reference count of the object and, more importantly for your question, the variable's value will automatically be set to nil when the referenced object gets deallocated.

Since the variable must allow for a nil value, it must be optional. This is why non-optional weak variables are disallowed.

Do not declare viewController to be implicitly unwrapped (using !). Make it a proper optional (using ?).

rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • The question was not about what is weak type, or how to avoid a compilation error. The question was why weak optional type is disallowed. I believe, I've made the point quite clear. – cyanide Sep 08 '18 at 02:44
  • A propos, changing "!" to "?" shouldn't make any difference, apart from need to explicitly unwrap viewController all the time. – cyanide Sep 08 '18 at 02:51
  • 1
    My answer specifically explains why a weak variable must be optional. In short, because only an optional can be nil and a weak variable can be nil. – rmaddy Sep 08 '18 at 02:54
  • 1
    And using ! Is wrong because such a variable should never be nil. – rmaddy Sep 08 '18 at 02:54
  • All right, a non-optional variable can't be set to nil, so its reference count never becomes 0. This suggests that standard reference-counting approach is not applicable to non-optinal type. Mark it as an answer, even though it raises more questions :) The good news is that I can safely use non-optional types without fear to cause a dead lock. – cyanide Sep 08 '18 at 06:35
  • 1
    @cyanide Sorry but your conclusions are wrong. A non-optional (and non-weak of course) variable to a reference type fully involves standard reference counting and most certainly can cause a reference cycle (I believe that's what you meant by "dead lock"). If you don't want the variable reference to involve reference counting, use weak. If you don't want the variable reference to possible cause a reference cycle, use weak. Since weak variables can be nil, the weak variable must also be optional. – rmaddy Sep 08 '18 at 15:31