I can't find any official documentation on this and there's mixed opinions out there.
In the following situation, all is well.
final class MyVC: UIViewController {
var space: Space!
private let tableView = MenuCategoriesTableView()
private let tableViewHandler = MenuCategoriesTableViewHandler()
override func viewDidLoad() {
super.viewDidLoad()
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
NSLayoutConstraint.activate([
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
tableView.dataSource = tableViewHandler
tableView.delegate = tableViewHandler
tableViewHandler.didSelectRow = { [unowned self] option in
let category = option.makeCategory()
if category.items.count > 0 {
let controller = MenuItemsViewController()
controller.title = option.rawValue
controller.space = self.space
self.show(controller, sender: self)
} else {
// whatever
}
}
}
}
However, if I make the following change, I no longer need to use unowned self
, but I'm still concerned about capture self. Should I be concerned? If not, why?
final class MyVC: UIViewController {
...etc...
override func viewDidLoad() {
super.viewDidLoad()
...etc...
func categorySelected(_ option: MenuOption, _ category: MenuCategory) {
let controller = MenuItemsViewController()
controller.title = option.rawValue
controller.space = space
show(controller, sender: self)
}
tableViewHandler.didSelectRow = { option in
let category = option.makeCategory()
if category.items.count > 0 {
categorySelected(option, category)
} else {
// whatever
}
}
}
}
When you assign a closure to tableViewHandler.didSelectRow
, you assign to it and retain whatever that closure captures.
self
is retaining tableViewHandler
.
Therefore, the danger is that you will refer to self
within the closure. If you do, that's a retain cycle.
And this might not be due to referring to self
explicitly. Any mention of a property or method of self
is an implicit reference to self
.
Okay, so with that out of the way, let's examine the closure.
You do not mention self
implicitly or explicitly in the body of the closure. However, you do call a local method, categorySelected
. Therefore, you capture this method.
And categorySelected
does mention self
. Therefore, it captures self
(because every function is a closure).
Thus there is a potential retain cycle and you should continue to say unowned self
to prevent a retain cycle.
(I presume that the compiler can't help you here by warning of the retain cycle; there's too much complexity. It's a problem you just have to solve by human reason.)