Reputation: 223
I have a UIBarButtonItem
in the right side of my navigation that has an image of a gear and presents my settings view controller. I can get it to work properly when I create the button in setupNavigationBar()
, but it doesn't work if I create the button as a property. I can't wrap my head around what would be different about these two scenarios. The button is present in both situations, but the functionality isn't.
This version doesn't work
class DecksController: UIViewController {
let settingsBarButton: UIBarButtonItem = {
let barButton = UIBarButtonItem(image: #imageLiteral(resourceName: "settings"), style: .plain, target: self, action: #selector(presentSettings))
return barButton
}()
override func viewDidLoad() {
super.viewDidLoad()
setupNavigationBar()
}
@objc func presentSettings() {
let settingsController = SettingsController()
self.navigationController?.pushViewController(settingsController, animated: true)
}
func setupNavigationBar() {
self.navigationItem.rightBarButtonItem = settingsBarButton
}
}
This version does work
class DecksController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
setupNavigationBar()
}
@objc func presentSettings() {
let settingsController = SettingsController()
self.navigationController?.pushViewController(settingsController, animated: true)
}
func setupNavigationBar() {
let settingsBarButton = UIBarButtonItem(image: #imageLiteral(resourceName: "settings"), style: .plain, target: self, action: #selector(presentSettings))
self.navigationItem.rightBarButtonItem = settingsBarButton
}
}
Upvotes: 1
Views: 48
Reputation: 535138
As you've discovered, it makes a big difference where this line occurs:
let barButton = UIBarButtonItem(image: #imageLiteral(resourceName: "settings"),
style: .plain, target: self, action: #selector(presentSettings))
The problem is the target:self
part. When the bar button item is configured as part of an instance property initializer (your first example), the instance doesn't exist yet — it is what we are initializing. So self
has no meaning, and the button ends up with no target
. Therefore, tapping the button does nothing.
(Actually, to be quite technical, self
is the class, but that's not a helpful thing to know.)
In your second example, that line is part of viewDidLoad
, which runs considerably after the view controller instance has come into existence and has been initialized. viewDidLoad
is an instance method, in fact. So self
is the instance, as you expect.
Upvotes: 2