How to Build an iOS Unit Converter App with Swift – Part 1

Hello world! In this post, we’re going to start building our first real-world app: a unit converter! With it, we hope to quickly convert between different units of length. This is Part 1 of the Unit Converter app post. In this part, we’ll learn about the Model-View-Controller pattern of iOS, UIPickerView, Swift enumerations, and static methods. We’ll also finish our UI and the code that will compute the conversion. In the next post, we’ll wire our UI t o our controller and code the core functionality of our Unit Converter app.

The source for the two-part post can be found here.

Learn iOS by building real apps

Check out The Complete iOS Development Course – Build 14 Apps with Swift 2 on Zenva Academy to learn Swift 2 and iOS development from the ground-up with an expert trainer.

Did you come across any errors in this tutorial? Please let us know by completing this form and we’ll look into it!

FREE COURSES
Python Blog Image

FINAL DAYS: Unlock coding courses in Unity, Godot, Unreal, Python and more.

Model-View-Controller Pattern (MVC)

When dealing with a system that has many moving parts it’s helpful to have some form of system design that helps us keep everything distinct. Imagine the mess our app would be if we had storyboards, Swift source code, and other components wildly about in our iOS project! To prevent this disaster from occurring, we have design patterns we follow to try to keep our code as segmented as possible. Similar to the concept of encapsulation in object-oriented programming languages, we want to make sure our components are separated from each other. For this, we use the Model-View-Controller (MVC) pattern. The MVC Pattern is now ubiquitously used in both mobile and desktop development.

Units - 1

The above figure is an illustration of the components of the MVC pattern. There’s the model, view, and controller. The model can be any kind of backend such as a database or web server. It can also be any kind of structure that holds or stores data somewhere, like a local key-value pairing system. The view is pretty self-explanatory: it’s the UI that’s presented to the user. The controller is the most crucial component that allows for communication between the model and the view. However, the view and the model don’t even know the other exists! This is so we can make changes to the model or the view and we only need to update the controller instead of all three components! (The view in most case is the component that is updated the most frequently.) The MVC Pattern is now ubiquitously used in both mobile and desktop development.

Specifically, iOS requires us to implement the MVC pattern very tightly. This is why we have UIViewController and storyboards. The storyboards act as our views. Each storyboard is bound to a UIViewController subclass. That acts as our controller. The model is something that we have to build independent of our controller and view. As stated above, it’s so we can make changes to our model and only need to alter our controller.

Unit Converter

Let’s get started on our Unit Converter app!

Open up Xcode and let’s create a new Single View App. We’ll call it UnitConverter, and you can change the organization name and identifier to anything you want. Make sure the language is set to Swift, and the device is iPhone. You can uncheck all of the checkboxes below since we won’t be doing anything involving core data or testing.

First, let’s create our UI. Open up the main storyboard. We need an input field for the user to enter data into, an output, and two views to select from a finite list of items. For the input and output, we’ll use UITextFields. To select from a finite list of options, as in our units, we need to use a UIPickerView. Below is the UI that we’re going to build.

Units - 2

First, drag out two UITextFields and align them so they are of equal width. Don’t worry about setting them up to be exactly the same width since we’ll use an autolayout constraint to handle this. Next, find a UIPickerView and drag it out right under the two UITextViews. The reason we’ll only need a single UIPickerView is because we can segment it into two pickers: one for the “from” unit and another for the “to” unit. Position a UIButton, centered horizontally, directly below the UIPicker.

Now we can get into autolayout for these views. First, select the left UITextField and pin it on all sides. Do the same for the second UITextField. In order to set the equal widths of the two UITextFields, select both of them and the Equal Widths constraint in the pin menu. For the second UITextField, in the Attributes Inspector, scroll down and uncheck “Enabled” so that users can’t enter anything into the output! Select the first one and change the Keyboard type to Decimal pad so users can’t enter characters!

For the UIPickerView, add constraints to all sides of the view except the top, since we’ve already added top constraints due to the UIPickerView. For the UIButton, add the constraint to center the UIButton horizontally. Change the text of the button to say “Convert”.

Now we’re done with autolayout! We can move on to some source code. First, let’s build our converter object. To make things easier for us, we’re going to use Swift enums as a special type of class. Create a new file by going to File->New and creating a new Swift file. We’ll call ours Unit. Afterwards, we should be presented with a single screen with a single code line that imports the Foundation framework. We won’t need it, but leave it in there.

Before we build our model, we first need to know what enums are and how they work in Swift. An enumeration (enum for short) is essentially a list of constants that developers use to represent different states. For example, the simplest state we could represent with an enum would be one for on and off. We could create a Swift enum like the following to encapsulation that representation

enum LightState {
    case on, off
}

After we have defined an enum, we can use it as a variable type.

var bedroomLight: LightState = LightState.on
bedroomLight = .on
bedroomLight = .off

Notice that after we’ve assigned a variable to be a case of an enum, it can’t be the case of another enum. This way, we can omit the enum name entirely and just type in a period followed by the case in the enum.

Let’s look at our specific application of enums. We want to be able to encode the different types of units we can convert. To do this, we can create an enum containing cases for all of our units like the following.

enum Unit: Int {
    case inch = 0, centimeter, foot, meter, mile
}

Now that we have an encoding for the different units, we need a way to convert between them. We could create a new Swift class to do this and a static method. But we can actually code methods inside of an enum! Take a look at the following code snippet.

enum Unit: Int {
    case inch = 0, centimeter, foot, meter, mile
    
    func convertTo(unit to: Unit, value val: Double) -> Double? {
        return nil;
    }
}

We have an instance method inside our enum! After creating a variable of that enum type, we can simply call someUnit.convertTo(unit: .YARD, value: 4.0)  and we’ll get a value that converted 4.0 from the current unit of that enum variable to a yard. The implementation of this function is fairly trivial: check the current unit we’re on (using self ), check the unit we’re converting to, adjust the multiplication constant appropriate and perform the multiplication. Below is the code.

func convertTo(unit to: Unit, value val: Double) -> Double {
    var constant = 1.0
    switch self {
    case .inch:
        if to == .centimeter {
            constant = 2.54
        } else if to == .foot {
            constant = 0.08333333
        } else if to == .meter {
            constant = 0.0254
        } else if to == .mile {
            constant = 1.5783e-5
        }
        
    case .centimeter:
        if to == .inch {
            constant = 0.0393701
        } else if to == .foot {
            constant = 0.0328084
        } else if to == .meter {
            constant = 0.01
        } else if to == .mile {
            constant = 6.2137e-6
        }
        
    case .foot:
        if to == .inch {
            constant = 12;
        } else if to == .centimeter {
            constant = 30.48
        } else if to == .meter {
            constant = 0.3048
        } else if to == .mile {
            constant = 0.000189394
        }
        
    case .meter:
        if to == .inch {
            constant = 39.3701
        } else if to == .centimeter {
            constant = 100
        } else if to == .foot {
            constant = 3.28084
        } else if to == .mile {
            constant = 0.000621371
        }
        
    case .mile:
        if to == .inch {
            constant = 63360
        } else if to == .centimeter {
            constant = 160934
        } else if to == .foot {
            constant = 5280
        } else if to == .meter {
            constant = 1609.34
        }
    }
    
    return constant * val
}

There’s one more thing we have to do. Since we’re dealing with strings, we need a way to convert from a string to a case in our enum. For this, we can create a new static function in our enum that will simply check string equality for all of our cases and return the appropriate case. A static function is a function that doesn’t require an instance to execute. We just use the name of class, the invocation operator (period .), and the name of the static function.

static func fromString(_ string: String) -> Unit? {
    if string == "inch" {
        return .inch
    } else if string == "centimeter" {
        return .centimeter
    } else if string == "foot" {
        return .foot
    } else if string == "meter" {
        return .meter
    } else if string == "mile" {
        return .mile
    } else {
        return nil
    }
}

Note that the return type of this function is an optional. In the event that the input string wasn’t a valid case, we return nil. However, since we’ll be using a UIPickerView, we won’t ever get to this else clause since the user has to choose between a finite set of options; in other words, they can’t add their own!

This completes our view and model as well as Part 1 of our unit converter app! In the next post, we’ll get into the controller and link the model and view!