1

The Swift book says that "to prevent strong reference cycles, delegates are declared as weak references."

protocol SomeDelegate: AnyObject {
  
}

class viewController: UIViewController, SomeDelegate {
  weak var delegate: SomeDelegate?
  
  override func viewDidLoad() {
    delegate = self
  }
}

Say the class parameterizes a struct with that delegate

class viewController: UIViewController, SomeDelegate {
  weak var delegate: SomeDelegate?
  
  override func viewDidLoad() {
    delegate = self
    let exampleView = ExampleView(delegate: delegate)
    let hostingController = UIHostingController(rootView: exampleView)
    self.present(hostingController, animated: true)
  }
}

struct ExampleView: View {
  var delegate: SomeDelegate!
  
  var body: some View {
    Text("")
  }
}

Should the delegate property in the struct also be marked with weak?

Curiosity
  • 544
  • 1
  • 15
  • 29
  • 1
    A struct cannot meaningfully have a delegate. A struct is a value. It lacks identity. There can be many copies of ExampleView. Every time you pass a struct to a function, it makes a copy. They do not all have to be on screen. (This is how View differs from UIView. A UIView represents part of the screen. A View represents *information* about part of the screen.) What would it mean for them to all have the same delegate? It's like attaching a delegate to "the number 4." – Rob Napier Oct 13 '21 at 18:19
  • In my broader non-simplified use, the delegate is a coordinator that handles navigation, so the SwiftUI view would be calling one of the delegates functions to dismiss and navigate away. – Curiosity Oct 13 '21 at 18:28

1 Answers1

1

You want the object that owns the delegate to be using a weak reference to its delegate, so in your case, ExampleView. The fact that you've declared a reference to the delegate in your View Controller doesn't actually serve a purpose here, unless you planned on using it outside of the viewDidLoad() block. But you can already do that anyway, since you can reference self any time.

You get this out of the box anyway, because that VC conforms to the SomeDelegate protocol, so you can just use self.

The book is suggesting you use a weak reference to self here because you don't want to retain anything once self no longer exists; by making this a weak reference, the delegate is destroyed once it is no longer needed.

class viewController: UIViewController, SomeDelegate {
  override func viewDidLoad() {
    let exampleView = ExampleView(delegate: self)
    //                                      ^ Note self here, not delegate
    let hostingController = UIHostingController(rootView: exampleView)
    self.present(hostingController, animated: true)
  }
}

struct ExampleView: View {
  weak var delegate: SomeDelegate?
  // ^ weak here, optional here  ^
  var body: some View {
    Text("")
  }
}

There's very little reason you would ever want to reference the delegate from ExampleView in the controller directly anyway, since the delegate protocol methods are now called by the delegate (the View Controller) not the view itself. But if for some reason you did, you could check that the delegate is set, and then reference it like:

if let delegate = exampleView.delegate {
    // do something with delegate
    // I'm probably not accounting for optional unwrapping here
}
brandonscript
  • 68,675
  • 32
  • 163
  • 220