Swift
UIBarButtonItem
iOS Development
Mobile App Development
Programming Tutorial

How to set the action for a UIBarButtonItem in Swift

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

Introduction

UIBarButtonItem uses UIKit's target-action pattern. You attach a target object and a selector, and UIKit calls that selector when the user taps the button.

The main mistake is to think of a bar button as a standalone view. In practice, it is a control item owned by a navigation bar or toolbar, so its action needs to be wired from the view controller that manages that bar.

Create the Button Programmatically

The most common setup happens inside a UIViewController. You create the item, point target at self, and pass a selector for an @objc method.

swift
1import UIKit
2
3final class DetailViewController: UIViewController {
4    override func viewDidLoad() {
5        super.viewDidLoad()
6        view.backgroundColor = .systemBackground
7        title = "Details"
8
9        navigationItem.rightBarButtonItem = UIBarButtonItem(
10            title: "Save",
11            style: .done,
12            target: self,
13            action: #selector(saveTapped)
14        )
15    }
16
17    @objc private func saveTapped() {
18        print("Save button tapped")
19    }
20}

This is enough for text buttons. The selector must reference a method visible to the Objective-C runtime, which is why @objc is required.

Use System Items or Images

If you want a standard icon such as Add, Edit, or Trash, use one of the built-in system items. These provide consistent behavior and styling across iOS.

swift
1import UIKit
2
3final class InboxViewController: UIViewController {
4    override func viewDidLoad() {
5        super.viewDidLoad()
6
7        navigationItem.rightBarButtonItem = UIBarButtonItem(
8            barButtonSystemItem: .add,
9            target: self,
10            action: #selector(addMessage)
11        )
12    }
13
14    @objc private func addMessage() {
15        print("Create a new message")
16    }
17}

You can also initialize with an image:

swift
1let refresh = UIBarButtonItem(
2    image: UIImage(systemName: "arrow.clockwise"),
3    style: .plain,
4    target: self,
5    action: #selector(refreshData)
6)

That is often cleaner than using a custom UIButton unless you truly need fully custom layout.

Connect an Action from Storyboard or Interface Builder

If the bar button item is created in Interface Builder, the action is still just a method on the view controller. Control-drag from the button item to the controller and create an @IBAction.

swift
1import UIKit
2
3final class SettingsViewController: UIViewController {
4    @IBAction private func doneTapped(_ sender: UIBarButtonItem) {
5        dismiss(animated: true)
6    }
7}

This method receives the sender, which is useful when multiple buttons share similar logic.

Disable or Update the Button Dynamically

A bar button often depends on state. For example, a Save button should stay disabled until the form becomes valid.

swift
1import UIKit
2
3final class EditProfileViewController: UIViewController {
4    private var saveButton: UIBarButtonItem!
5    private var hasValidChanges = false {
6        didSet {
7            saveButton.isEnabled = hasValidChanges
8        }
9    }
10
11    override func viewDidLoad() {
12        super.viewDidLoad()
13
14        saveButton = UIBarButtonItem(
15            title: "Save",
16            style: .done,
17            target: self,
18            action: #selector(saveProfile)
19        )
20        saveButton.isEnabled = false
21        navigationItem.rightBarButtonItem = saveButton
22    }
23
24    @objc private func saveProfile() {
25        print("Saving profile")
26    }
27}

Keeping a reference to the button makes it easy to toggle isEnabled, change the title, or swap the item entirely.

Prefer Clear Ownership of the Action

The target should usually be the view controller that owns the screen. That keeps navigation and UI state in one place. If the action needs business logic, call into a service or view model from that method rather than trying to make the bar button manage logic by itself.

For modern apps using UIAction, note that UIBarButtonItem still commonly relies on selectors in UIKit-heavy codebases. If you are working in pure SwiftUI, use ToolbarItem instead; do not try to force UIKit patterns into SwiftUI screens.

Common Pitfalls

  • Forgetting @objc on the selector method. The app will compile in some cases but the selector wiring will fail at runtime.
  • Setting target to nil accidentally. That removes the explicit receiver and can make the action travel the responder chain in unexpected ways.
  • Creating the button without storing it when you need later updates. If the enabled state changes, keep a reference.
  • Using a custom view too early. Standard initializers are simpler, more accessible, and better aligned with UIKit behavior.
  • Wiring the action in the wrong controller. The visible navigation item belongs to the active view controller, not some parent helper object.

Summary

  • 'UIBarButtonItem actions use the target-action pattern.'
  • Programmatic setup with target: self and action: #selector(...) is the standard approach.
  • '@objc methods are required for selector-based callbacks.'
  • Store a reference when the item needs to be enabled, disabled, or replaced later.
  • Use standard bar button items unless a custom view is truly necessary.

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Interview Questions practice on Codemia

Over 8,000 real interview questions from top companies, searchable by company and role.

Browse interview questions

All Rights Reserved.