Create a cryptocurrency tracking app with push notifications using Swift and Laravel - Part 2: The iOS app
Tags: pusher, realtime, ios, swift
Published: 2018-11-22 10:47:12

---
title: Create a cryptocurrency tracking app with push notifications using Swift and Laravel - Part 2: The iOS app
published: true
description: 
tags: pusher, realtime, ios, swift
---

> You will need the following installed on your machine: Xcode, the Laravel CLI, SQLite, and Cocoapods. Familiarity with the Xcode IDE will be helpful. You should have completed part one of the series.

In the [first part](https://dev.to/neo/create-a-cryptocurrency-tracking-app-with-push-notifications-using-swift-and-laravel---part-1-the-backend-2mdh) of this article, we started developing our cryptocurrency alert application. We developed the backend of the application that will power the iOS application. As it stands, our backend application can return settings for a device based on its UUID, save the settings for a device based on its UUID and also it can figure out what devices to send push notifications to when the currencies update.

In this part, we will focus on creating the iOS application using Swift and Xcode.

## Prerequisites

To follow along you need the following requirements:

- Completed the [part one](http://#) of this article.
- [Xcode](https://developer.apple.com/xcode) installed on your machine.
- Knowledge of the Xcode IDE.
- Basic knowledge using the [Laravel framework](https://laravel.com/).
- Basic knowledge of the [Swift programming language](http://developer.apple.com/swift).
- [Laravel CLI](https://laravel.com/docs/5.6/installation) installed on your machine.
- SQLite installed on your machine. [Installation guide](http://www.sqlitetutorial.net/download-install-sqlite/).
- [Cocoapods](https://guides.cocoapods.org/using/getting-started.html) installed on your machine.
- [Pusher Beams](https://pusher.com/beams) and [Channels](https://pusher.com/channels) application.

## What we will be building

We already started out by building the backend of the application using Laravel. So next, we will build the iOS application using Swift. If you want to test the push notifications then you will need to run the application on a live device.

### How the client application will work

For the client app, the iOS application, we will create a simple list that will display the available currencies and the current prices to the dollar. Whenever the price of the cryptocurrency changes, we will trigger an event using Pusher Channels so the prices are updated.

From the application, you will be able to set a minimum and maximum price change when you want to be alerted. For instance, you can configure the application to send a push notification to the application when the price of one Etherium (ETH) goes below $500. You can also configure the application to receive a notification when the price of Bitcoin goes above $5000.

### How the application will look

When we are done with the application, here's how the application will look:

![](//images.ctfassets.net/1es3ne0caaid/1K08NTSdaoIIqWQ2YAyOqo/4efdb4fa01a2ee599bf5b71561a717a4/ios-cryptocurrency-part-1-demo.gif)

Let’s get started.

## Setting up your client application

Launch Xcode and click **Create a new Xcode project**. Select **Single View App** and click **Next**. Enter your **Product Name**, we will call our project _cryptoalat_, and select **Swift** from the **Language** options. You can also change any other detail you wish to on the screen then click **Next**.

### Installing dependencies

Now you have your Xcode project. Close Xcode and open a terminal window. `cd` to the iOS project directory in terminal and run the command below to create a Podfile:

```
    $ pod init

```

> The Podfile is a specification that describes the dependencies of the targets of one or more Xcode projects. The file should simply be named Podfile. All the examples in the guides are based on CocoaPods version 1.0 and onwards. - [Cocoapods Guides](https://guides.cocoapods.org/using/the-podfile.html)

This will generate a new file called `Podfile` in the root of your project. Open this file in any editor and update the file as seen below:

```
    // File: Podfile
    platform :ios, '11.0'

    target 'cryptoalat' do
      use_frameworks!

      pod 'Alamofire', '~> 4.7.2'
      pod 'PushNotifications', '~> 0.10.8'
      pod 'PusherSwift', '~> 6.1.0'
      pod 'NotificationBannerSwift', '~> 1.6.3'
    end

```

> If you used a project name other than cryptoalat, then change it in the Podfile to match your project’s target name.

Go to terminal and run the command below to install your dependencies:

```
    $ pod install

```

When the installation is complete, you will have a `*.xcworkspace` file in the root of your project. Open this file in Xcode and let’s start developing our cryptocurrency alert application.

## Building the iOS application

### Creating our storyboard

The first thing we need to do is design our storyboard for the application. This is what we want the storyboard to look like when we are done.

![](//images.ctfassets.net/1es3ne0caaid/3CgFeKuZnyMkQ0Kseaw2Gk/9e4a0a12e87fe5685f30c563d9f3ea8d/ios-cryptocurrency-part-2-storyboard.png)

Open the `Main.storyboard` file and design as seen above.

Above we have three scenes. The first scene, which is the entry point, is the launch scene. We then draw a manual segue with an identifier called **Main**. Then we set the segue **Kind** to **Present Modally**. This will present the next scene which is a navigation view controller. Navigation controllers already have an attached root view controller by default.

We will use this attached view controller, which is a `TableViewController`, as the main view for our application. It’ll list the available currencies and show us a text field that allows us to change the setting for that currency when it is tapped.

On the third scene, we set the reuse identifier of the cells to **coin** and we drag two labels to the prototype cell. The first label will be for the coin name and the second label will be for the price.

Now that we have the scenes, let’s create some controllers and view classes and connect them to our storyboard scenes.

### Creating your controllers

In Xcode, create a new class `LaunchViewController` and paste the contents of the file below into it:

```
    <span class="hljs-keyword">import</span> UIKit

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LaunchViewController</span>: <span class="hljs-title">UIViewController</span> </span>{

        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">viewDidAppear</span><span class="hljs-params">(<span class="hljs-number">_</span> animated: Bool)</span></span> {
            <span class="hljs-keyword">super</span>.viewDidAppear(animated)

            <span class="hljs-type">SettingsService</span>.shared.loadSettings {
                <span class="hljs-keyword">self</span>.routeToMainController()
            }
        }

        <span class="hljs-keyword">fileprivate</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">routeToMainController</span><span class="hljs-params">()</span></span> {
            performSegue(withIdentifier: <span class="hljs-string">"Main"</span>, sender: <span class="hljs-keyword">self</span>)
        }
    }
```

> Set the controller as the custom class for the first scene in the `Main.storyboard` file.

In the code, we load the settings using a `SettingsService` class we will create later. When the settings are loaded for the device, we then call the `routeToMainController` method, which routes the application to the main controller using the **Main** segue we created earlier.

The next controller we will be creating will be the `CoinsTableViewController`. This will be the controller that will be tied to the third scene which is the main scene.

Create the `CoinsTableViewController` and replace the contents with the following code;

```
    <span class="hljs-keyword">import</span> UIKit
    <span class="hljs-keyword">import</span> PusherSwift
    <span class="hljs-keyword">import</span> NotificationBannerSwift

    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Coin</span> </span>{
        <span class="hljs-keyword">let</span> name: <span class="hljs-type">String</span>
        <span class="hljs-keyword">let</span> rate: <span class="hljs-type">Float</span>
    }

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CoinsTableViewController</span>: <span class="hljs-title">UITableViewController</span> </span>{

        <span class="hljs-keyword">var</span> coins: [<span class="hljs-type">Coin</span>] = []

        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">viewDidLoad</span><span class="hljs-params">()</span></span> {
            <span class="hljs-keyword">super</span>.viewDidLoad()
        }

        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">numberOfSections</span><span class="hljs-params">(<span class="hljs-keyword">in</span> tableView: UITableView)</span></span> -> <span class="hljs-type">Int</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>
        }

        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">tableView</span><span class="hljs-params">(<span class="hljs-number">_</span> tableView: UITableView, numberOfRowsInSection section: Int)</span></span> -> <span class="hljs-type">Int</span> {
            <span class="hljs-keyword">return</span> coins.<span class="hljs-built_in">count</span>
        }

        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">tableView</span><span class="hljs-params">(<span class="hljs-number">_</span> tableView: UITableView, cellForRowAt indexPath: IndexPath)</span></span> -> <span class="hljs-type">UITableViewCell</span> {
            <span class="hljs-keyword">let</span> coin = coins[indexPath.row]
            <span class="hljs-keyword">let</span> cell = tableView.dequeueReusableCell(withIdentifier: <span class="hljs-string">"coin"</span>, <span class="hljs-keyword">for</span>: indexPath) <span class="hljs-keyword">as</span>! <span class="hljs-type">CoinTableViewCell</span>

            cell.name.text = <span class="hljs-string">"1 \(coin.name) ="</span>
            cell.amount.text = <span class="hljs-string">"$\(String(coin.rate))"</span>

            <span class="hljs-keyword">return</span> cell
        }
    }
```

> Set the controller as the custom class for the first scene in the `Main.storyboard` file.

Above we have defined the `Coin` struct and it has a `name` and `rate` property. We have the controller which we define the `coins` property as an array of `Coin`s. We then have some boilerplate code that comes with creating a table view controller.

The `numberOfSections` method specifies how many sections the table will have. In the first `tableView` method, we return the number of `coins` available and in the second `tableView` method, we define how we want each row to be handled.

### Creating other supporting classes

If you noticed in the code above, we referenced a `CoinTableViewCell` as the class for each row in the last `tableView` method. Let’s create that.

Create a `CoinTableViewCell` class and paste the following code into it:

```
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CoinTableViewCell</span>: <span class="hljs-title">UITableViewCell</span> </span>{
        <span class="hljs-meta">@IBOutlet</span> <span class="hljs-keyword">weak</span> <span class="hljs-keyword">var</span> name: <span class="hljs-type">UILabel</span>!    
        <span class="hljs-meta">@IBOutlet</span> <span class="hljs-keyword">weak</span> <span class="hljs-keyword">var</span> amount: <span class="hljs-type">UILabel</span>!
    }
```

Open the `Main.storyboard` file and set the class as the custom class for the prototype cell in the third scene of the `Main.storyboard` file. When you have set the class, connect the `@IBOutlet`s as specified in the cell class above.

The next class we need to create is the `SettingsService`. This class will be responsible for updating and fetching the settings for the device.

Create a new `SettingsService` class and replace the contents with the following code:

```
    <span class="hljs-keyword">import</span> Foundation
    <span class="hljs-keyword">import</span> Alamofire
    <span class="hljs-keyword">import</span> NotificationBannerSwift

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SettingsService</span> </span>{
        <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> key = <span class="hljs-string">"CryptoAlat"</span>
        <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> shared = <span class="hljs-type">SettingsService</span>()

        <span class="hljs-keyword">var</span> settings: <span class="hljs-type">Settings</span>? {
            <span class="hljs-keyword">get</span> {
                <span class="hljs-keyword">return</span> <span class="hljs-keyword">self</span>.getCachedSettings()
            }
            <span class="hljs-keyword">set</span>(settings) {
                <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> settings = settings {
                    <span class="hljs-keyword">self</span>.updateCachedSettings(settings)
                }
            }
        }

        <span class="hljs-keyword">private</span> <span class="hljs-keyword">init</span>() {}

        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">loadSettings</span><span class="hljs-params">(completion: @escaping<span class="hljs-params">()</span></span></span> -> <span class="hljs-type">Void</span>) {
            fetchRemoteSettings { settings <span class="hljs-keyword">in</span>
                <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> settings = settings <span class="hljs-keyword">else</span> {
                    <span class="hljs-keyword">return</span> <span class="hljs-keyword">self</span>.saveSettings(<span class="hljs-keyword">self</span>.defaultSettings()) { <span class="hljs-number">_</span> <span class="hljs-keyword">in</span>
                        completion()
                    }
                }

                <span class="hljs-keyword">self</span>.updateCachedSettings(settings)
                completion()
            }
        }

        <span class="hljs-keyword">fileprivate</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">defaultSettings</span><span class="hljs-params">()</span></span> -> <span class="hljs-type">Settings</span> {
            <span class="hljs-keyword">return</span> <span class="hljs-type">Settings</span>(
                btc_min_notify: <span class="hljs-number">0</span>, 
                btc_max_notify: <span class="hljs-number">0</span>, 
                eth_min_notify: <span class="hljs-number">0</span>, 
                eth_max_notify: <span class="hljs-number">0</span>
            )
        }

        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">saveSettings</span><span class="hljs-params">(<span class="hljs-number">_</span> settings: Settings, completion: @escaping<span class="hljs-params">(Bool)</span></span></span> -> <span class="hljs-type">Void</span>) {
            updateRemoteSettings(settings, completion: { saved <span class="hljs-keyword">in</span>
                <span class="hljs-keyword">if</span> saved {
                    <span class="hljs-keyword">self</span>.updateCachedSettings(settings)
                }

                completion(saved)
            })
        }

        <span class="hljs-keyword">fileprivate</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">fetchRemoteSettings</span><span class="hljs-params">(completion: @escaping <span class="hljs-params">(Settings?)</span></span></span> -> <span class="hljs-type">Void</span>) {
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> deviceID = <span class="hljs-type">AppConstants</span>.deviceIDFormatted <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">return</span> completion(<span class="hljs-literal">nil</span>)
            }

            <span class="hljs-keyword">let</span> url = <span class="hljs-string">"\(AppConstants.API_URL)?u=\(deviceID)"</span>
            <span class="hljs-type">Alamofire</span>.request(url).validate().responseJSON { resp <span class="hljs-keyword">in</span>
                <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> data = resp.data, resp.result.isSuccess {
                    <span class="hljs-keyword">let</span> decoder = <span class="hljs-type">JSONDecoder</span>()
                    <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> settings = <span class="hljs-keyword">try</span>? decoder.decode(<span class="hljs-type">Settings</span>.<span class="hljs-keyword">self</span>, from: data) {
                        <span class="hljs-keyword">return</span> completion(settings)
                    }
                }

                completion(<span class="hljs-literal">nil</span>)
            }
        }

        <span class="hljs-keyword">fileprivate</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">updateRemoteSettings</span><span class="hljs-params">(<span class="hljs-number">_</span> settings: Settings, completion: @escaping<span class="hljs-params">(Bool)</span></span></span> -> <span class="hljs-type">Void</span>) {
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> deviceID = <span class="hljs-type">AppConstants</span>.deviceIDFormatted <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">return</span> completion(<span class="hljs-literal">false</span>)
            }

            <span class="hljs-keyword">let</span> params = settings.toParams()
            <span class="hljs-keyword">let</span> url = <span class="hljs-string">"\(AppConstants.API_URL)?u=\(deviceID)"</span>
            <span class="hljs-type">Alamofire</span>.request(url, method: .post, parameters: params).validate().responseJSON { resp <span class="hljs-keyword">in</span>
                <span class="hljs-keyword">guard</span> resp.result.isSuccess, <span class="hljs-keyword">let</span> res = resp.result.value <span class="hljs-keyword">as</span>? [<span class="hljs-type">String</span>: <span class="hljs-type">String</span>] <span class="hljs-keyword">else</span> {
                    <span class="hljs-keyword">return</span> <span class="hljs-type">StatusBarNotificationBanner</span>(title: <span class="hljs-string">"Failed to update settings."</span>, style: .danger).show()
                }

                completion((res[<span class="hljs-string">"status"</span>] == <span class="hljs-string">"success"</span>))
            }
        }

        <span class="hljs-keyword">fileprivate</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">updateCachedSettings</span><span class="hljs-params">(<span class="hljs-number">_</span> settings: Settings)</span></span> {
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> encodedSettings = <span class="hljs-keyword">try</span>? <span class="hljs-type">JSONEncoder</span>().encode(settings) {
                <span class="hljs-type">UserDefaults</span>.standard.<span class="hljs-keyword">set</span>(encodedSettings, forKey: <span class="hljs-type">SettingsService</span>.key)
            }
        }

        <span class="hljs-keyword">fileprivate</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">getCachedSettings</span><span class="hljs-params">()</span></span> -> <span class="hljs-type">Settings</span>? {
            <span class="hljs-keyword">let</span> defaults = <span class="hljs-type">UserDefaults</span>.standard
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> data = defaults.object(forKey: <span class="hljs-type">SettingsService</span>.key) <span class="hljs-keyword">as</span>? <span class="hljs-type">Data</span> {
                <span class="hljs-keyword">let</span> decoder = <span class="hljs-type">JSONDecoder</span>()
                <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> decodedSettings = <span class="hljs-keyword">try</span>? decoder.decode(<span class="hljs-type">Settings</span>.<span class="hljs-keyword">self</span>, from: data) {
                    <span class="hljs-keyword">return</span> decodedSettings
                }
            }

            <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
        }
    }
```

Above we have the `SettingsService`. The first method `loadSettings` loads the settings from the API and then saves it locally. If there is no setting remotely, it calls the `defaultSettings` method and saves the response to the API.

The `saveSettings` method saves the `Settings` remotely using `updateRemoteSettings` and then locally using `updateCachedSettings`. The `fetchRemoteSettings` gets the settings from the API and decodes the response using the [Swift decodable API](https://blog.pusher.com/swift-4-decoding-json-codable/).

Next, let’s define the `Settings` struct and have it extend `Codable`. In the same file for the `SettingsService`, add this above the `SettingsService` class definition:

```
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">Settings</span>: <span class="hljs-title">Codable</span> </span>{
        <span class="hljs-keyword">var</span> btc_min_notify: <span class="hljs-type">Int</span>?
        <span class="hljs-keyword">var</span> btc_max_notify: <span class="hljs-type">Int</span>?
        <span class="hljs-keyword">var</span> eth_min_notify: <span class="hljs-type">Int</span>?
        <span class="hljs-keyword">var</span> eth_max_notify: <span class="hljs-type">Int</span>?

        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">toParams</span><span class="hljs-params">()</span></span> -> <span class="hljs-type">Parameters</span> {
            <span class="hljs-keyword">var</span> params: <span class="hljs-type">Parameters</span> = [:]

            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> btcMin = btc_min_notify { params[<span class="hljs-string">"btc_min_notify"</span>] = btcMin }
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> btcMax = btc_max_notify { params[<span class="hljs-string">"btc_max_notify"</span>] = btcMax }
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> ethMin = eth_min_notify { params[<span class="hljs-string">"eth_min_notify"</span>] = ethMin }
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> ethMax = eth_max_notify { params[<span class="hljs-string">"eth_max_notify"</span>] = ethMax }

            <span class="hljs-keyword">return</span> params
        }
    }
```

Above we have a simple `Settings` struct that conforms to `Codable`. We also have a `toParams` method that converts the properties to a `Parameters` type so we can use it with [Alamofire](https://github.com/Alamofire/Alamofire) when making requests.

One last class we need to create is `AppConstants`. We will use this class to keep all the data that we expect to remain constant and unchanged throughout the lifetime of the application.

Create a `AppConstants` file and paste the following code:

```
    <span class="hljs-keyword">import</span> UIKit

    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">AppConstants</span> </span>{
        <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> <span class="hljs-type">API_URL</span> = <span class="hljs-string">"http://127.0.0.1:8000/api/settings"</span>
        <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> deviceID = <span class="hljs-type">UIDevice</span>.current.identifierForVendor?.uuidString
        <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> deviceIDFormatted = <span class="hljs-type">AppConstants</span>.deviceID?.replacingOccurrences(of: <span class="hljs-string">"-"</span>, with: <span class="hljs-string">"_"</span>).lowercased()
        <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> <span class="hljs-type">PUSHER_INSTANCE_ID</span> = <span class="hljs-string">"PUSHER_BEAMS_INSTANCE_ID"</span>
        <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> <span class="hljs-type">PUSHER_APP_KEY</span> = <span class="hljs-string">"PUSHER_APP_KEY"</span>
        <span class="hljs-keyword">static</span> <span class="hljs-keyword">let</span> <span class="hljs-type">PUSHER_APP_CLUSTER</span> = <span class="hljs-string">"PUSHER_APP_CLUSTER"</span>
    }
```

> Replace the `PUSHER_*` keys with the values gotten from the Pusher Channels and Beams dashboard.

### Updating the settings for the device

Now that we have defined the settings service, let’s update our controller so the user can set the minimum and maximum prices for each currency.

Open the `CoinsTableViewController` class and add the following method:

```
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">tableView</span><span class="hljs-params">(<span class="hljs-number">_</span> tableView: UITableView, didSelectRowAt indexPath: IndexPath)</span></span> {
        <span class="hljs-keyword">let</span> coin = coins[indexPath.row]

        <span class="hljs-keyword">var</span> minTextField: <span class="hljs-type">UITextField</span>?
        <span class="hljs-keyword">var</span> maxTextField: <span class="hljs-type">UITextField</span>?

        <span class="hljs-keyword">let</span> title = <span class="hljs-string">"Manage \(coin.name) alerts"</span>
        <span class="hljs-keyword">let</span> message = <span class="hljs-string">"Notification will be sent to you when price exceeds or goes below minimum and maximum price. Set to zero to turn off notification."</span>

        <span class="hljs-keyword">let</span> alert = <span class="hljs-type">UIAlertController</span>(title: title, message: message, preferredStyle: .alert)

        alert.addTextField { textfield <span class="hljs-keyword">in</span>
            minTextField = textfield
            textfield.placeholder = <span class="hljs-string">"Alert when price is below"</span>
        }

        alert.addTextField { textfield <span class="hljs-keyword">in</span>
            maxTextField = textfield
            textfield.placeholder = <span class="hljs-string">"Alert when price is above"</span>
        }

        alert.addAction(<span class="hljs-type">UIAlertAction</span>(title: <span class="hljs-string">"Cancel"</span>, style: .cancel, handler: <span class="hljs-literal">nil</span>))

        alert.addAction(<span class="hljs-type">UIAlertAction</span>(title: <span class="hljs-string">"Save"</span>, style: .<span class="hljs-keyword">default</span>, handler: { action <span class="hljs-keyword">in</span>
            <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> minPrice = minTextField?.text, <span class="hljs-keyword">let</span> maxPrice = maxTextField?.text <span class="hljs-keyword">else</span> {
                <span class="hljs-keyword">return</span> <span class="hljs-type">StatusBarNotificationBanner</span>(title: <span class="hljs-string">"Invalid min or max price"</span>, style: .danger).show()
            }

            <span class="hljs-keyword">var</span> btcMin: <span class="hljs-type">Int</span>?, btcMax: <span class="hljs-type">Int</span>?, ethMin: <span class="hljs-type">Int</span>?, ethMax: <span class="hljs-type">Int</span>?

            <span class="hljs-keyword">switch</span> coin.name {
            <span class="hljs-keyword">case</span> <span class="hljs-string">"BTC"</span>:
                btcMin = <span class="hljs-type">Int</span>(minPrice)
                btcMax = <span class="hljs-type">Int</span>(maxPrice)
            <span class="hljs-keyword">case</span> <span class="hljs-string">"ETH"</span>:
                ethMin = <span class="hljs-type">Int</span>(minPrice)
                ethMax = <span class="hljs-type">Int</span>(maxPrice)
            <span class="hljs-keyword">default</span>:
                <span class="hljs-keyword">return</span>
            }

            <span class="hljs-keyword">let</span> settings = <span class="hljs-type">Settings</span>(
                btc_min_notify: btcMin,
                btc_max_notify: btcMax,
                eth_min_notify: ethMin,
                eth_max_notify: ethMax
            )

            <span class="hljs-type">SettingsService</span>.shared.saveSettings(settings, completion: { saved <span class="hljs-keyword">in</span>
                <span class="hljs-keyword">if</span> saved {
                    <span class="hljs-type">StatusBarNotificationBanner</span>(title: <span class="hljs-string">"Saved successfully"</span>).show()
                }
            })
        }))

        present(alert, animated: <span class="hljs-literal">true</span>, completion: <span class="hljs-literal">nil</span>)
    }
```

The method above is automatically called when a row is selected. In this method, we display a `UIAlertController` with two text fields for the minimum price and the maximum price. When the prices are submitted, the `SettingsService` we created earlier takes care of updating the values both locally and remotely.

### Adding realtime cryptocurrency update support

Open the `CoinsTableViewController` and add the `pusher` property to the class as seen below:

`    <span class="hljs-keyword">var</span> pusher: <span class="hljs-type">Pusher</span>!`Then replace the `viewDidLoad` method with the following code:

```
    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">viewDidLoad</span><span class="hljs-params">()</span></span> {
        <span class="hljs-keyword">super</span>.viewDidLoad()

        pusher = <span class="hljs-type">Pusher</span>(
            key: <span class="hljs-type">AppConstants</span>.<span class="hljs-type">PUSHER_APP_KEY</span>, 
            options: <span class="hljs-type">PusherClientOptions</span>(host: .cluster(<span class="hljs-type">AppConstants</span>.<span class="hljs-type">PUSHER_APP_CLUSTER</span>))
        )

        <span class="hljs-keyword">let</span> channel = pusher.subscribe(<span class="hljs-string">"currency-update"</span>)

        <span class="hljs-keyword">let</span> <span class="hljs-number">_</span> = channel.bind(eventName: <span class="hljs-string">"currency.updated"</span>) { data <span class="hljs-keyword">in</span>
            <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> data = data <span class="hljs-keyword">as</span>? [<span class="hljs-type">String</span>: [<span class="hljs-type">String</span>: [<span class="hljs-type">String</span>: <span class="hljs-type">Float</span>]]] {
                <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> payload = data[<span class="hljs-string">"payload"</span>] <span class="hljs-keyword">else</span> { <span class="hljs-keyword">return</span> }

                <span class="hljs-keyword">self</span>.coins = []

                <span class="hljs-keyword">for</span> (coin, deets) <span class="hljs-keyword">in</span> payload {
                    <span class="hljs-keyword">guard</span> <span class="hljs-keyword">let</span> currentPrice = deets[<span class="hljs-string">"current"</span>] <span class="hljs-keyword">else</span> { <span class="hljs-keyword">return</span> }
                    <span class="hljs-keyword">self</span>.coins.append(<span class="hljs-type">Coin</span>(name: coin, rate: currentPrice))
                }

                <span class="hljs-type">Dispatch</span>.main.async {
                    <span class="hljs-keyword">self</span>.tableView.reloadData()
                }
            }
        }

        pusher.connect()
    }
```

In the code above, we are using the [Pusher Swift SDK](https://pusher.com/docs/ios_quick_start) to subscribe to our `currency-update` Pusher Channel. We then subscribe to the `currency.updated` event on that channel. Whenever that event is triggered, we refresh the price of the cryptocurrency in realtime.

### Adding push notifications to our iOS new application

To add push notification support, open the `AppDelegate` class and replace the contents with the following:

```
    <span class="hljs-keyword">import</span> UIKit
    <span class="hljs-keyword">import</span> PushNotifications

    <span class="hljs-meta">@UIApplicationMain</span>
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AppDelegate</span>: <span class="hljs-title">UIResponder</span>, <span class="hljs-title">UIApplicationDelegate</span> </span>{

        <span class="hljs-keyword">var</span> window: <span class="hljs-type">UIWindow</span>?

        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">application</span><span class="hljs-params">(<span class="hljs-number">_</span> application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: <span class="hljs-keyword">Any</span>]?)</span></span> -> <span class="hljs-type">Bool</span> {
            <span class="hljs-type">PushNotifications</span>.shared.start(instanceId: <span class="hljs-type">AppConstants</span>.<span class="hljs-type">PUSHER_INSTANCE_ID</span>)
            <span class="hljs-type">PushNotifications</span>.shared.registerForRemoteNotifications()
            <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>
        }

        <span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">application</span><span class="hljs-params">(<span class="hljs-number">_</span> application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)</span></span> {
            <span class="hljs-type">PushNotifications</span>.shared.registerDeviceToken(deviceToken) {
                <span class="hljs-keyword">if</span> <span class="hljs-keyword">let</span> deviceID = <span class="hljs-type">AppConstants</span>.deviceIDFormatted {
                    <span class="hljs-keyword">try</span>? <span class="hljs-type">PushNotifications</span>.shared.subscribe(interest: <span class="hljs-string">"\(deviceID)_eth_changed"</span>)
                    <span class="hljs-keyword">try</span>? <span class="hljs-type">PushNotifications</span>.shared.subscribe(interest: <span class="hljs-string">"\(deviceID)_btc_changed"</span>)
                }
            }
        }
    }
```

In the class above, we use the [Pusher Beams Swift SDK](https://docs.pusher.com/push-notifications/reference/ios) to register the device for push notifications. We then subscribe to the `*_eth_changed` and `*_btc_changed` interests, where `*` is the device’s unique UUID.

Now that we have completed the logic for the application, let’s enable push notifications on the application in Xcode.

In the project navigator, select your project, and click on the **Capabilities** tab. [Enable Push Notifications](http://help.apple.com/xcode/mac/current/#/devdfd3d04a1) by turning the switch ON.

![](//images.ctfassets.net/1es3ne0caaid/7wLtGQ4Y00EUWiKgw6oQoE/8eb22b60c3271e6d0e47646c6423a7ad/ios-cryptocurrency-part-2-enable-push.png)

This will create an entitlements file in the root of your project. With that, you have provisioned your application to fully receive push notifications.

### Allowing our application to connect locally

If you are going to be testing the app’s backend using a local server, then there is one last thing we need to do. Open the `info.plist` file and add an entry to the `plist` file to allow connection to our local server:

![](//images.ctfassets.net/1es3ne0caaid/5SXadC36VOcMs22Ooayw44/a7272c2b7126b3195878e1bcfad3e57b/ios-cryptocurrency-part-2-local-connection.png)

That’s all. We can run our application. However, **remember that to demo the push notifications, you will need an actual iOS device as simulators cannot receive push notifications.** If you are using a physical device, you’ll need to expose your local API using [Ngrok](https://ngrok.com) and then change the `API_URL` **In**`AppConstants`.

Anytime you want to update the currency prices, run the command below manually in your Laravel application:

```
    $ php artisan schedule:run

```

Here is a screen recording of the application in action:

![](//images.ctfassets.net/1es3ne0caaid/1K08NTSdaoIIqWQ2YAyOqo/4efdb4fa01a2ee599bf5b71561a717a4/ios-cryptocurrency-part-1-demo.gif)

## Conclusion

In this article, we have been able to see how easy it is to create a cryptocurrency alert website using Laravel, Swift, Pusher Channels and Pusher Beams. The source code to the application built in this article is available on [GitHub](https://github.com/neoighodaro/cryptocurrency-alert-ios-app).

This post first appeared on the [Pusher blog](https://pusher.com/tutorials/cryptocurrency-tracking-swift-laravel-part-2).