Generic Global elegant way to add bar button items to any UIViewController of the project : <p>Usually we have a predefined set of <code>UIBarButtonItem</code> in the project that can be used in the project and multiple times like a left menu button to open a side menu, it can be used in different <code>UIViewController</code>s also a close button that dismiss the presented view controller. </p>

<p>The classic way is to add these buttons as needed, but this introduce a code duplication and we all want to avoid that.</p>

<p>My come up with an approach, but it's far from being perfect :  </p>

<pre><code>enum BarButtonItemType {
    case menu, close, notification
}

enum BarButtonItemPosition{
    case right, left
}

extension UIViewController {

    func add(barButtons:[BarButtonItemType], position: BarButtonItemPosition) {

        let barButtonItems = barButtons.map { rightBarButtonType -&gt; UIBarButtonItem in
            switch rightBarButtonType {
            case .menu:
                return UIBarButtonItem(image: UIImage(named:"menu"),
                    style: .plain,
                    target: self,
                    action: #selector(presentLeftMenu(_:)))
            case .notification:
                return UIBarButtonItem(image: UIImage(named:"notification"),
                style: .plain,
                target: self,
                action: #selector(showNotification(_:)))
            case .close:
                return UIBarButtonItem(image: UIImage(named:"close"),
                    style: .plain,
                    target: self,
                    action: #selector(dismissController(_:)))
            }
        }

        switch position {
        case .right:
            self.navigationItem.rightBarButtonItems = barButtonItems
        case .left:
            self.navigationItem.leftBarButtonItems  = barButtonItems
        }
    }

    // MARK: Actions
    @objc fileprivate func presentLeftMenu(_ sender:AnyObject) {
        self.parent?.presentLeftMenuViewController(sender)
    }

    @objc fileprivate func dismissController(_ sender:AnyObject) {
        self.dismiss(animated: true, completion: nil)
    }

   @objc fileprivate func showNotification(_ sender:AnyObject) {
       let notificationViewController = UINavigationController(rootViewController:NotificationViewController())
       self.present(notificationViewController, animated: true, completion: nil)
   }
}
</code></pre>

<p>and then the usage:</p>

<pre><code>override func viewDidLoad() {
    super.viewDidLoad()
    self.add(barButtons: [.close], position: .right)
    self.add(barButtons: [.menu], position: .left)
}
</code></pre>

<p>The limitations of my approach are:</p>

<ul>
<li><p>The extension needs to know how to instantiate new view controller (case of notification for example) and what if viewController must be inited with parameters</p></li>
<li><p>It assumes that you only want to present a <code>UIViewController</code></p></li>
<li><p>Not elegant.</p></li>
</ul>

<p>I am sure that there is better way with Swift language and protocol oriented programming that can achieve the intended result with more flexibility, any thoughts ?</p>
