Creating custom UIViews can be very useful for many reasons; code reusability, view controller code reduction and improve maintainability. It enables you to build one component and use it in multiple places around your application. This will reduce the total number of lines in your project and enable you to make changes to your component in one place as opposed to many. View controllers can often get bloated with code that can be delegated to the views of the controller.


Here is an example of a custom UIView XIB. The view contains one button, which when pressed fires a delegate method that should be handled inside your ViewController.

Screen Shot 2018-01-31 at 15.54.42

Here is the code for the TestView and the TestViewDelegate. The TestView has a container view, UIButton, and delegate. Ensure that the container view and UIButton are connected up to the XIB properly. You will need to create an IBAction to handle the button press on the TestView, inside this action method you will fire the delegate method which will be sent to the parent UIViewController that conforms to TestViewDelegate.

import UIKit
// MARK: TestViewDelegate
protocol TestViewDelegate: class {
func testView(_ testView: TestView, didSelect button: UIButton)
// MARK: TestView
class TestView: UIView {
// MARK: Delegates
weak var delegate: TestViewDelegate?
// MARK: Outlets
@IBOutlet var contentView: UIView!
@IBOutlet var button: UIButton!
// MARK: UIView Methods
override func awakeFromNib() {
// MARK: Action Methods
@IBAction func buttonPressed(sender: Any?) {
guard let button = sender as? UIButton else {
delegate?.testView(self, didSelect: button)
// MARK: Helper Methods
private func setupButton() {
button.backgroundColor = .red
button.setTitleColor(.white, for: .normal)
button.layer.cornerRadius = 5
button.clipsToBounds = true
// MARK: Init Methods
override init(frame: CGRect) {
super.init(frame: frame)
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
private func commonInit() {
Bundle.main.loadNibNamed(String(describing: TestView.self), owner: self, options: nil)
contentView.frame = self.bounds
contentView.autoresizingMask = [.flexibleWidth, .flexibleHeight]

view raw


hosted with ❤ by GitHub

Now that our TestView is set up correctly, we simply have to place it onto our UIViewController, create an IBOutlet to it and set its delegate properly. Once we have done those three steps, the TestView will fire back a delegate call every time its “Action” button is pressed. Enabling our TestViewController to handle that button press further, in this case by printing a simple statement.

import UIKit
// MARK: TestViewController
class TestViewController: UIViewController {
// MARK: Outlets
@IBOutlet var testView: TestView!
// MARK: View Methods
override func viewDidLoad() {
testView.delegate = self
// MARK: TestViewDelegate Methods
extension TestViewController: TestViewDelegate {
func testView(_ testView: TestView, didSelect button: UIButton) {
guard let buttonText = button.titleLabel?.text else {
print("\(buttonText) pressed")


Here is the full source code for the project:

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.