Build a price tracker for Bitcoin, Ethereum, & more in Swift

Max Stein
maxste.in

--

This is part 2 of my Ethereum/Bitcoin price tracking app tutorial. You can read part 1 here if you’d like to get caught up. I wrote this tutorial so you can follow it even if you didn’t read part 1, however.

I wrote the first part of this tutorial on October 10th 2017. Since then the Bitcoin price has gone from $4,805 to $16,764 (as of December 21st, 2017) over a 348% increase!

I would say now is a great time to add Bitcoin support to our price tracker. Now that we’ll be adding a second currency it’d be nice to make our solution scalable to many currencies. When we’re done the app will look like this:

Supports Bitcoin, Ethereum, Litecoin, Ripple, Monero, and NEO

Lets jump right in. Download the starter project here then open “CryptoTracker.xcodeproj”. You’ll need Xcode 9 to open it up since the project is built in Swift 4.

Open up “Assets.xcassets” from the projects pane on the left-hand side, then expand the “Currencies” folder. You’ll see the project already has logos for the six currencies we’ll be supporting in this tutorial.

Now, select “Main.storyboard” from the projects pane and you’ll see a UITableViewController with an embedded UITableViewCell. Expand from the left-hand panel “Crypto Table View Controller Scene → Crypto Table View Controller → Table View →CryptoTableViewCell →Content View” then select CryptoTableViewCell. From there you should tap the “Connections Inspector” which is the last button on the top right in the panel on the right-hand side. (Looks like an → symbol inside a circle):

The Table View is of type CryptoTableViewController and the cell is of type CryptoTableViewCell. These correspond to those two files within the projects pane. The cell has 3 subviews. The first is a UIImageView which will show the icon for a currency, named currencyImageView. The bold text that says “Cryptocurrency Name” is a UILabel named currencyName. The text underneath that that says “$0.00” will show our price in USD, named currencyPrice.

Open up “CryptoTableViewCell.swift” and you’ll see it has @IBOutlet’s for the currencyImageView, currencyName, and currencyPrice. This is connected to the UIImageView, and two UILabels we just looked at in “Main.storyboard”.

A data model for Cryptocurrencies

Now its time to start adding support for some Cryptocurrencies. Create a new file (⌘+n), select “Swift File” as the type and click next in the bottom right. In the “Save as” prompt name the file “CurrencyType” and click “Create” in the bottom right of the prompt.

Add the following enum on line 10 of the new file:

CurrencyType is an enum which we will use to represent six different Cryptocurrencies, Bitcoin (BTC), Ethereum (ETH), Litecoin (LTC), Ripple (XRP), Monero (XMR), and NEO (NEO). Its a String type enum so if you try to read its rawValue it will return the String its associated with. For instance, CurrencyType.btc.rawValue returns the StringBTC”.

In part 1 we used the CryptoCompare API to get the price of Ethereum by performing a GET request at the following URL:

let apiURL = URL(string: “https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=USD")

Our enum cases have a rawValue associated with them mapping to each of the six Cryptocurrencies. We can use that to modify this URL to get the value for each of them. To do so hit enter on line 17 then add the following on line 18 of the file:

By leveraging the rawValue we can now get the respective URL for any Cryptocurrency we add to the CurrencyType enum. For exampleCurrencyType.btc.apiURL returns the URL:

https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD

Going to this URL will get back the BTC price in USD.

Now to display the name of these currencies within the cell, we create a variable called name. Add the following to line 23 underneath the apiURL var:

This will allow us to get the name back for a CurrencyType as a String. For instance, CurrencyType.xrp.name will return the StringRipple”.

Next, we’ll want to be able to get the image for each of the currencies icons. To use the UIImage API we must first import UIKit, to do that replace import Foundation on line 9 with the following:

import UIKit

Now that we can use UIImage's API lets create a var called image by adding this on line 40:

#imageLiteral extracts the image with the specified resourceName seen above from the “Assets.xcassets” catalog we looked at earlier. It returns a guaranteed non-nil image since the name maps with that image’s name within the Asset catalog. If you try deleting #imageLiteral(resourceName: "Bitcoin") above and start typing the word “Bitcoin” you should be able to select the “Bitcoin” #imageLiteral from autocomplete:

Hitting Enter on the image in autocomplete will put the #imageLiteral in this spot

And now we have an icon and a name for each of our Cryptocurrencies. Next step is to actually be able to get the current value for each of these. For this, we need to make a GET request to the CryptoCompare API.

Recall earlier that we already have a var called apiURL which maps to the correct URL for each of our currencies prices. We can use that URL to make a request to the API and store the price as a String. Add the following func on line 58 that we’ll use for this request:

Our requestValue function has a completion block which will return an NSNumber?. We are using a completion block here because a URLRequest is a background operation, meaning that the UI work of rendering the app occurs while the function is operating. Once this function completes its work in the background we can use the value var it gets back on the main thread through a completion handler.

The first step in the function is to safely unwrap apiURL, recall earlier that the type of apiURL was URL? so to use it for requests it must be unwrapped first. Our guard statement does that and gives us an apiURL instance of type URL.

Now lets start the request. Hit enter on line 64 then add this on line 65:

First, we perform a dataTask request that takes in the URL, using Apple’s URLSession API. It returns Data from the call, a response(which returns information about the call), and an optional Error in the event of failure.

We do request.resume() at the end which starts the call. At this point, we are not doing anything with the information returned. Let’s replace the TODO with the following:

This confirms that the data we got back isn’t nil and that there weren’t any errors. In the else case we send back nil since no data was found and try to print the Error, for safety we unwrap it using ? to get back a description of the Error and if no description is found we print an empty String. The Error should never be nil here but using optionals is a good habit to get into for writing safe code.

Now we have the Data safely unwrapped and made sure there aren’t any errors, now its time to fetch the USD value from the JSON response we got back from the server. To do so add the following on line 71 underneath the guard block we just added:

To read the JSON Data, we use the JSONSerialization class from Apple, which takes JSON Data and converts it into a Dictionary. Since this method throws an Error in the case of failure, we need to add do at the beginning and catch to handle errors.

Once we have the Dictionary we can start reading values, inside the JSON Dictionary is the key “USD” which contains the US price of the currency as a number so we cast that value to NSNumber.

If for whatever reason we can’t get back the value we pass nil to the completion block again and return. If we do get the value back safely though we pass it to the completion block.

Setting up our cell to display Cryptocurrencies

Alright, now that the CurrencyType stores a name, image, and value for each of our currencies we can now use it in our CryptoTableViewCell, open up “CryptoTableViewCell.swift” from the projects pane on the left-hand side.

To display the value we get back from the requestValue function we need a way to format the value as US currency. Let’s write a private extension for NSNumber to do this. Add the following on line 18 of the file underneath the CryptoTableViewCell:

By making this an extension of NSNumber we can access the var from an NSNumber instance.

The formattedCurrencyString uses NumberFormatter, a class from Apple that takes numbers and represents them in various text formats. By setting the locale to en_us and the numberStyle to .currency we can use the NumberFormatter to represent the value in US dollars.

We then use the NumberFormatter’s string(from:) method by passing in self which is our instance of NSNumber. This returns an optional String? instance formatting the number as US dollars.

Now let’s take care of formatting our cell with the CurrencyType data model. To do so we need to set the currencyImageView, currencyName, and currencyPrice with the values from a CurrencyType instance. Add the following on line 16 right under those 3 @IBOutlets:

formatCell is a function that takes in a CurrencyType instance, sets the text for currencyName equal to currencyType.name and the image for currencyImageView equal to currencyType.image. It also performs the requestValue function to fetch the value of the currency.

requestValue has a completion block which returns with an instance of NSNumber? which either holds the value of the currency or nil. This happens in the background so we use Apple’s Dispatch API to set the text for currencyPrice on the main thread using DispatchQueue.main.async.

Since value is optional we can unwrap it as value? and then get the US currency String using the formattedCurrencyString variable we wrote. Since this operation could return nil we handle the failure case using the ?? operator. ?? means if value?.formattedCurrencyString is nil it will return whats on the right-hand side instead.

In this case, we return the StringFailed to get price”. It’s a good idea when working with API’s to assume errors can happen, and to handle these without force unwrapping using ! which would crash the app if one of our currency API calls failed.

Populate the table view with our Cryptocurrencies

Now that the cell is able to display a Cryptocurrency we need to hook up the CryptoTableViewController to pass in some CurrencyType instances to display. Open up “CryptoTableViewController.swift” then add the following on line 12:

The currencies Array stores an instance of each of the six Cryptocurrencies we support. reuseIdentifier is a String describing CryptoTableViewCell.self which will return the name of the class “CryptoTableViewCell”. The reuseIdentifier will be used when we dequeue CryptoTableViewCell instances later on.

Next, let’s implement numberOfRowsInSection which tells the UITableView how many rows we will display. This should be equal to the number of currencies. To do so hit enter under the reuseIdentifier then add the following on line 15:

currencies.count returns the number of items in the currencies array, which is six.

Now let’s populate the cells with our currencies. To do so we will be using the cellForRowAtIndexPath method. Hit enter on line 18 then add the following on line 19:

cellForRowAtIndexPath expects back an instance of UITableViewCell which is ready to be displayed. We use the UITableView function dequeueReusableCell which uses the reuseIdentifier and the current IndexPath to get an instance of our CryptoTableViewCell.

Since dequeueReusableCell returns CryptoTableViewCell as its super class UITableViewCell we have to then cast our tableViewCell instance as a CryptoTableViewCell. From there we can call the formatCell function we wrote to actually populate the cell with the CurrencyType for the current row, which we get back by using currencies[indexPath.row].

Finally, we return the tableViewCell instance so the UITableView can prepare to display it.

Giving it a test drive

Now that everything is set up let’s try running the app (⌘+R). You should see six cells populate our table view like this:

Finishing Touches

The app looks good but can be even better with a few finishing touches. By adding a header and footer to our table view we can provide a bit more info to the user.

Let’s start by adding a simple header. Hit enter on line 28 then add the following on line 29:

titleForHeaderInSection allows you to add a String that will appear above all the rows in our UITableView. Since we only have a single section we don’t need to worry about the section Int that this function provides us.

Something else that would be nice to provide users is a timestamp for when the request happened. We can put this in the footer of the table. Hit enter on line 32 then add the following to line 33 to add that:

DateFormatter is an Apple API which allows you to take a Date instance and display it in a variety of different formats. To create a simple human-readable Date we set the dateStyle to .long and the timeStyle to .medium.

We then get an instance of Date() which returns the current Date. Like NumberFormatter we use the string(from:) method to extract a String from the formatter. Finally, we add the StringUpdated on ” to appear before the formatted date String.

Now run the app (⌘+R) again and it should look like this:

Conclusion

There you have it! If you had any trouble getting the app working you can download the final version here. It has some added comments and documentation as well.

Thanks so much for taking the time to read this. If this tutorial helped you I would appreciate you holding down that 👏 button below! If you’re a Github user a ⭐️ on the CryptoTracker Github page would be great too!

--

--

Max Stein
maxste.in

iOS Engineer @ Amazon, Blockchain Engineer & Enthusiast. Creator of https://maxste.in, a full-service App development company. @maxsteinapps