Leadrains
Leadrains

Reputation: 23

Swift, confusion with UIBarButtonItem

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?

Upvotes: 2

Views: 1462

Answers (4)

Berlin Raj
Berlin Raj

Reputation: 124

UIBatButtonItem may contain UIButton

enter image description here 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

Upvotes: 0

Sophy Swicz
Sophy Swicz

Reputation: 1357

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:)))
}

Upvotes: 1

Lalit kumar
Lalit kumar

Reputation: 2197

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


}

Upvotes: 0

Ramesh.G
Ramesh.G

Reputation: 359

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){


        }
    }

Upvotes: 0

Related Questions