问题
I began to learn Swift recently. When I tried to make my first App
I got confused with UIBarButtonItem
. If I put let UIBarButtonItem
initialization outside the viewDidLoad()
function, nothing happens when I press the Next Button.
class ViewController: UIViewController, UITextFieldDelegate {
let rightBarButton: UIBarButtonItem = UIBarButtonItem(title: "Next", style: .plain, target: self, action: #selector(onClickNext(button:)))
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
self.navigationItem.rightBarButtonItem = rightBarButton
}
func onClickNext(button: UIBarButtonItem) {
print("should push view controller")
}
}
However, when I put the initialization
into the viewDidLoad()
function, the output area does output the sentense that I set in the onClickNext(button:)
function.
class ViewController: UIViewController, UITextFieldDelegate {
var rightBarButton: UIBarButtonItem?
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = .white
self.rightBarButton = UIBarButtonItem(title: "Next", style: .plain, target: self, action: #selector(onClickNext(button:)))
self.navigationItem.rightBarButtonItem = rightBarButton
}
func onClickNext(button: UIBarButtonItem) {
print("should push view controller")
}
}
Also, I I found that when I put the initialization
outside the viewDidLoad()
function, and I add a UITextField
to viewController
, the rightBarButton
works if I touch the textfield
before I press the button.
That make me confused. What is the mechanism?
回答1:
Well, maybe you are missing how a ViewController works inside.
First, viewDidLoad
is the area were you usually setup or initialize any view or properties of the view. This method is also called only once during the life of the view controller object. This means that self
already exists.
Knowing this, is important to understand what a let
property does, (from Apple)
A constant declaration defines an immutable binding between the constant name and the value of the initializer expression; after the value of a constant is set, it cannot be changed. That said, if a constant is initialized with a class object, the object itself can change, but the binding between the constant name and the object it refers to can’t.
Even though the upper area is where you declare variables and constants, is usually meant for simple initialization, it's an area for just telling the VC that there is an object that you want to work with and will have a class global scope, but the rest of functionality will be added when the view hierarchy gets loaded (means that the object does not depends of self, for example, when adding target to a button, you are referring to a method inside of self)....this variables or constants are called Stored Properties
In its simplest form, a stored property is a constant or variable that is stored as part of an instance of a particular class or structure. Stored properties can be either variable stored properties (introduced by the var keyword) or constant stored properties (introduced by the let keyword).
And finally, you have a lazy stored property that maybe can be applied for what you want:
A lazy stored property is a property whose initial value is not calculated until the first time it is used. You indicate a lazy stored property by writing the lazy modifier before its declaration.
Solution: create a lazy var stored property or add his properties inside ViewDidLoad (when self already exists)
lazy private var doneButtonItem : UIBarButtonItem = {
[unowned self] in
return UIBarButtonItem(title: "Next", style:UIBarButtonItemStyle.Plain, target: self, action: #selector(onClickNext(button:)))
}()
OR
let rightBarButton: UIBarButtonItem?
override func viewDidLoad() {
super.viewDidLoad()
rightBarButton = UIBarButtonItem(title: "Next", style: .plain, target: self, action: #selector(onClickNext(button:)))
}
回答2:
import UIKit
class ViewController: UIViewController {
var btnName = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
btnName.setImage(UIImage(named: "imagename"), for: .normal)
btnName.frame = CGRect(x:0,y: 0,width: 30,height: 30)
btnName.addTarget(self, action: #selector(addTargetActionForButton(:_)), for: .touchUpInside)
let rightBarButton = UIBarButtonItem(customView: btnName)
self.navigationItem.rightBarButtonItem = rightBarButton
}
func addTargetActionForButton(_ sender : UIButton){
}
}
回答3:
Your are taking let variable out side of viewDidLoad You can not take let global variable. if you want to take let than you need to declare inside viewDidLoad. Fore more info let and var check this link What is the difference between `let` and `var` in swift?
override func viewDidLoad() {
let rightBarButton: UIBarButtonItem = UIBarButtonItem(title: "Next", style: .plain, target: self, action: #selector(onClickNext(button:)))
super.viewDidLoad()
self.view.backgroundColor = .white
self.navigationItem.rightBarButtonItem = rightBarButton
}
回答4:
UIBatButtonItem may contain UIButton
above example image have UINavigationItem which contains LeftBarButtonItems ([UIBarButton]), and RightBarButtonItems([UIBarButtonItem]), each UIBarButtonItem contain UIButton
we can customise the UIButton to specify how to display in View And we can connect button action directly to the UIButton
来源:https://stackoverflow.com/questions/45408498/swift-confusion-with-uibarbuttonitem