Building Breather (Part 1 — Bonus): Populating the UI with sample data, namespacing with enums and formatting the data with Swift Extensions

Breather is an open-source iOS app that shows the weather, air pollution and asthma conditions around you.

Alexandros Baramilis
5 min readApr 12, 2019

To raise awareness about air pollution and practice my iOS skills at the same time, I’m building an open-source app where I apply some of the latest knowledge I gain about iOS, Swift and programming. Since there is a lot of information to digest, I’m splitting it into small manageable parts:

Populating the UI with sample data

I created some models that will hold the data that we need to display in this app:

The Breather models

I also made an extension that provides some sample data that I got by manually querying the APIs.

Some sample data

Now, in MainViewController, we can populate the UI with the sample data:

Populating the UI with sample data

This is a chunky piece of code, but basically we’re updating the UI with sample data on viewDidLoad and updating the air quality data when the segmented control value changes. The rest of the methods deal with appropriately formatting the data for display to the user. I will go through the parts that are the most worth mentioning.

Running the app with sample data

Namespacing with enums

You will notice some functions that are called like:

  • Asset.forIconCode(data.weather.iconCode)
  • Color.forTemperature(data.weather.temperature)
  • Text.forAQI(data.pollution.aqiUS)
  • Color.forAQI(data.pollution.aqiUS)
  • Color.forAsthmaRisk(data.asthma.risk)

These functions take the data and return the appropriate colour, text or icon.

This is a pattern that I like to use for constants that are used throughout the app.

I will give one example here and the rest you can find in the app.

Declaring constants with a Text enum

By declaring Text as an enum instead of a struct or a class, you prevent someone from trying to initialise an object from it. The only way to access it is through the static func that returns a String. So this is quite handy when you need to declare some constants in your project in a neat and safe way.

You can define Text in a separate Constants.swift file, or if you have a lot of constants, in a separate Text.swift file in a Constants folder.

In this example I gave it the common name Text, but if you’re planning for your code to be used alongside other people’s code, it’s better naming practice to prefix with your project’s name or initials, for example BreatherText or BRText or something, to avoid conflicts.

And you can of course define static lets instead of static functions, for example:

Namespacing with enum vs. struct

In this example you can also see that you get a compiler error if you try to initialise an enum.

And you can even nest enums to create a “Constants directory”:

Declaring constants with nested enums

Neat.

Encoding wind direction through a rotating UIImageView

The AirVisual API returns the wind direction in degrees like: North=0, East=90, South=180, West=270 and all the values in between.

To relay this information to the user, I decided to make a cute little compass icon and rotate it depending on the wind direction.

First, we need to convert the degrees to radians:

let rotationAngle = (CGFloat(data.weather.windDirection) * .pi) / 180.0

And then apply the transform.

windDirectionImageView.transform = CGAffineTransform(rotationAngle: rotationAngle)

Encoding wind direction with a compass (310 degrees)

Displaying a UILabel with subscripts

The final part is displaying the pollutants with the appropriate format.

AirVisual API returns the pollutants as codes for example “p2” for PM₂.₅.

First, we want to get the appropriate pollutant name and then we want to display it with the numbers in subscript.

To get the pollutant name, we add a handy static func to our Text enum, like before.

Main pollutant name for code returned by AirVisual API

These are the primary pollutants that pose a danger to human health. The riskiest pollutant at any given moment will dictate the AQI value, that’s why we have the main pollutant data. For example, if the API returns “p2”, it means the AQI value is based on the concentration of PM₂.₅.

PM₂.₅ is very frequently returned by the API as the main pollutant, because of its high danger to health. PM₂.₅ stands for particulate matter that is less than 2.5 micrometers in diameter. Because of its size, it can penetrate deep into the lungs and cause all sorts of health problems, including asthma, lung cancer, respiratory diseases, cardiovascular disease, birth defects, and premature death.

A scary metric: Particulate matter pollution was estimated to cause 3.22 million deaths globally in 2010!

Unfortunately, until we clean up our act as a species on this planet, there is not much we can do to protect ourselves on an individual level, other than to wear anti-pollution masks when we’re near traffic (my favourite one), or have a home filter if we live in the centre of the city.

And of course, spread the word as much as we can, so change can slowly take place. We can also help by reducing our energy consumption, reducing our waste by reusing and recycling things, avoid buying excess stuff we don’t really need, buying second hand items where we can, switching to a renewable energy provider or installing solar panels, driving electric cars, planting trees, investing in clean projects and going out in the streets and shouting!

You’re probably thinking: “You still haven’t told me how to display a UILabel with subscripts.” and you’re right.

For this, I made an extension on UILabel with a function that sets the attributedText property of UILabel with an attributed string that displays all the characters at the given indices in subscript.

It’s used like this:

Using setAttributedTextWithSubscripts extension on UILabel

For finding the indices of the subscripts, I made another extension on String, that finds the indices of all the numbers in a string.

Displaying a UILabel with subscripts

Keep reading → Part 2: Refactoring with MVVM and RxSwift.

--

--