I am trying to separate out my tableView's datasource into a separate delegate object. Since that delegate needs to access the tableview at some point I need a reference to the delegating object in the delegate; and since both are classes I need to avoid strong reference cycles by making the delegate weak
To achieve this I tried the following code.
class MyViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
weak var tableViewDelegate: UITableViewDataSource?
override func viewDidLoad() {
super.viewDidLoad()
tableViewDelegate = TableViewDelegate() // throwing a warning
tableView.dataSource = tableViewDelegate
}
}
When I try to instantiate the delegate Xcode throws a warning: "Instance will be immediately deallocated because property 'tableViewDelegate' is 'weak'"
So to fix it I do the following:
class MyViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
weak var tableViewDelegate: UITableViewDataSource?
override func viewDidLoad() {
super.viewDidLoad()
let delegate = TableViewDelegate() // worried this creates a strong reference.
self.tableViewDelegate = delegate
tableView.dataSource = delegate
}
}
Please confirm if the following is true or not: by initialising the delegate in the viewDidLoad() method I am not in danger of creating a strong reference because the variable that holds that instance is deallocated as soon as we leave the scope of that method. Or to put it another way: the only time we need to worry about a variable (which points to a class) creating a strong reference is if the variable is initialised at the class level, and hence will live on as long as the class does.
Is that correct?
Please confirm if the following is true or not: by initialising the delegate in the viewDidLoad() method I am not in danger of creating a strong reference because the variable that holds that instance is deallocated as soon as we leave the scope of that method.
Correct. The strong reference goes away as soon as the scope in which the let
is declared exits.
Unfortunately, that means your delegate will still be deallocated. All you have done is silence the warning.
Basically, you need to have a strong reference to the delegate somewhere or it will go away straight away. My feelings is that you should make the reference in MyViewController
strong. There will be no strong reference cycle as long as your delegate does not contain a strong reference to the view controller. If you need a reference to MyViewController
in the delegate, make that a weak one i.e. the view controller owns the delegate, not the delegate owns the view controller.
Response to the comment below:
almost all the tutorials I have found have the delegate property as weak, so it seems standard practice.
Yes it is fairly standard practice, there are exceptions including in Cocoa. However, it is standard practice to have a weak reference to the delegate in the delegating object. In your case, the delegating object is thew UITableView
not the MyViewController
. In your first example from the Internet, the FileImporter
is analogous to the UITableView
in your code. In the second example, the DetailViewController
is the delegating object.
If you think about it, your TableViewDelegate
is being used in place of making MyViewController
conform to the protocol. It makes absolute sense that the MyViewController
would own the delegate.