Use this to make your code clean in iOS

Islom Babaev
3 min readFeb 22, 2021
Keep a loose connection between two independent sources

If you are not familiar with how MVC in iOS should be structured, check out my previous post about MVC design pattern. This post explains how action callbacks can be handled using closures.

Storyboards are not the best way to approach iOS development, yet practical one. But keep in mind that we are trying to keep logic of view and view controller separate since most of the developers create outlets/actions inside a ViewController.swift file.

By creating IBOutlet and a respective IBAction of a UIButton underlying logic of ViewController.swift file is already broken.

Remember we divided view and VC into separate files and those should serve different purposes. In addition, it is also handy to setup button targets inside a view. However, how could we handle an action from VC when a button is tapped?

Take a closer look at setupTargets method that adds handleTap as its callback when a button is tapped. However, what is more conspicuous is the handleTap function that calls an optional function buttonClosure. It defines an optional function without any arguments passed and returns Void, this way we free VC from setting up targets and defining action callbacks.

If you are not new iOS development, closures are almost everywhere. The buttonClosure function we defined inside a ClosureView.swift is the same closure we are used to use in every coding process. However, it follows a bit different syntax in comparison to implementing them using completion handlers.

Major subtlety you need to pay close attention to is the [ weak self ] statement inside a closure. Whenever we reference a property of a view from VC, we need to encapsulate strong self as a weak self. Consequently, we would not have a memory leak if our VC is removed from memory.

Although simple print is used inside a closure, we can go far beyond that and pass some data as an argument to a closure.

Examine that we are passing an integer as a parameter to a closure and handleTap calls buttonClosure with an argument.

In ViewController we can reference that number passed in from a view and print it to the console.

Inspect the result of a closure:

Console log of a button being pressed in a simulator

TL;DR

  1. Declare targets inside a view, not a ViewController
    Add targets to your buttons/textFields and etc. inside a view
  2. Create an optional closure inside a view and invoke it in a target function of a button
  3. Retrieve the result as a weak self in ViewController
    Never forget to encapsulate a strong self as weak so as to avoid memory leak

--

--