Using SwiftUI in production (Part 2)

Chen Li
3 min readJun 13, 2020

In our last article, we walked through the experience of building the UI part of a production app, with SwiftUI. In this article (Part 2), we’ll cover how the UI module is interacting with the services: MeasurementService, HistoryDataService.

Initiating MeasurementService

MeasurementService is at the heart of the app’s data flow:
- It initiates hardware camera
- It takes the raw readings from camera, and passes raw readings to HeartRateCalculator, to actually calculate heart rate
- It periodically reads output from HeartRateCalculator, and update the stored latestHeartRate value (a state)
- Its states are observed by UI module

This is how we config MeasurementService, to start the hardware camera. Note that we marked progress, latestHeartRate, and state as @Published, so that UI module can observe them.

Start and Stop Measuring

We created dedicated functions, to start and stop a measurement.
1. In startMeasuring(), capture session is started, flashlight is turned on, idle timer is disabled, and a heart rate reading timer is scheduled. The state is moved to WaitingForFinger.
2. In stopMeasuring(), the config process is reversed. If the cancellation is initiated by the user, we move into NotMeasuring state; if the cancellation is called by the service itself, when enough data has been collected to conclude the bpm value, we move to Success state.

Process Camera Outputs

Camera outputs drive some of the states.
1. If we can’t find a finger on the camera (based on HSV value of the camera output), we’re still in WaitingForFinger state.
2. If the user’s finger is on the camera, we move to Measuring state.
3. If we’re in the middle of Measuring, and still need more camera data: we don’t change the state, and update progress value instead. This will update the ring widget’s progress.

The ring widget’s is updated, responding to MeasurementService’s progress value change

4. Once we measured long enough, we call stopMeasuring(), which will update state to Success.

HistoryDataService

As the name suggests, HistoryDataService allows writing and reading history data of measurement.
- It maintains a few states for UI module to observe: todayMin, todayMax, todayAverage, todayLatest.
- It has couple functions, to read and write heart rate history data. These functions are used to update the states.
- Underneath it, is the Realm database, a very easy-to-use mobile database.

Part 2 Summary

In this part, we walked through how to create the service layer, that keeps and updates states values for UI layer to render. In this service layer, we have a MeasurementService and a HistoryDataService; they serves different purposes; but from the perspective of data flow, they both serve states data for UI layer. States are the bridges between raw data (from camera or from database) and UI.

In the next part, I’ll talk about how we integrate existing UIViewController subclasses into out SwiftUI app. You can follow me on Twitter for more iOS dev tips.

--

--

Chen Li

Entrepreneur, prev engineering at Instagram & Apple. Twitter @chen_mobile.