Health Up Diaries 1: A Better HealthKit API

Image for post
Image for post

This is to be the first of an ongoing series of my experiences working on my app Health Up Display. I’m taking inspiration from other developers in the community who have done and are doing similar blogs about their own apps. Check out Brent Simmon’s old Vesper Sync Diary or the Slopes Diaries by Curtis Herbert for a few examples.

There are a few goals in launching this series of posts.

  1. A way to talk to myself out loud as I reason through these things.
  2. To possibly draw help from others who’ve already solved similar problems.
  3. Provide that same help to others further behind me in the learning curve.
  4. Use public accountability as a fire under my feet to provide the motivation needed to stay focused and finally ship this app.
  5. To give me a steady stream of content while I am still dipping my toes into the blogging waters.

Before we get started a little background is in order. Health Up Display is my health and fitness tracking app I’ve been working on, sadly, for a few years now. I wanted an app that combined the database viewing aspect of Health.app with a design styling more closely resembling the UI in Activity.app on iOS. I also wanted to address what I feel are a shortcomings in both apps. I like to think of this app as the product of those two apps if they had a baby. I haven’t made as much progress as I would’ve liked on the project yet, but I have made progress nonetheless, and have a very usable beta if you’d like to take a look. You can sign up here to try it out.

With that out of the way, we can move on to the topic of today’s diary entry.

A better API to interact with HealthKit

My app has a few classes designed to build these queries for me. They also form a centralized place and wrapper for my app to interact with HealthKit. I use these instances to retrieve health stats from the HealthKit database and then store them in my apps own data cache so the UI can be ready with your most recent stats as soon as you launch. You really don’t want to have to wait on the queries to return every time you launch the app. When the queries finally return newer data later, I update my cache and the UI layer of the app. These classes are full of these previously mentioned examples of code that just isn’t Swifty, and are also crying to be updated now that I understand more about Swift Style and even more about how to use and interact with HealthKit. Additionally soon I hope to get started on the Apple Watch component to this app and I’ll need to share a bunch of this code with that target as well. I have another fun pet project app called Mowing Meter that uses the iPhone’s motion co-processor chip to track your steps and distance while mowing the yard. I’m currently converting it to Swift and turning it into a “real” fitness tracker as well. That project could also utilize much of the same code.

The problem domain is this.

  1. This code needs updated to modern Swift naming conventions and less like Objective-C written in Swift.
  2. This modern Swift syntax needs to include a better query return Result type.

The solution

Current code

The Old Code

Aside from a few minor modifications from the Swift Migration Assistant, over a few iterations, these methods haven’t really been changed since the day I wrote them. Let’s break them down a little.

They build a query to retrieve their respective sample types based on the parameters passed in. The generated queries include a completion handler closure which accepts the query, returned samples, and an error if appropriate. As mentioned before that’s just not desirable in a modern Swift API. I did try to tackle that here by having these query factory methods take a closure for processing the results within the apps call site after first logging out an error if need be in the original query completion handler. I would then simply pass in the samples or an empty array to the caller’s results handler. This got the job done but still isn’t really ideal. The original caller gets an array, full or empty, regardless of the result from HealthKit. That’s fine for making the result to the caller non optional so it doesn’t have to be checked there or risk looping through non existent samples while processing them. If we are however looking at sharing this framework in multiple projects, some of them might need to handle a possible error within the original caller. An empty sample array keeps the app from crashing, but it won’t help you determine if there just aren’t any new samples or you may need to tell the app user they might need to provide authorization for your app to access that particular type of sample.

Next these method signatures aren’t very Swift looking and don’t really conform to modern naming conventions at all. To be honest they don’t even really look like Objective-C names to me, more like C++ or dare I say JavaScript, the horror! I did create a few sensible default parameters for a few of them, so you could omit them much of the time when calling, so that’s a plus at least. Also I did create typeAliases for the results handler closures to help keep the method signatures more readable but the rest of the parameters just don’t cut it. Modern Swift naming conventions state we should use prepositions, adjectives and adverbs combined with the types of the parameters to make it a clear readable signature at the call site. These are definitely falling short there.

Lastly when you take a look at those two methods you’ll notice they are nearly identical except for the typecast to the type of sample desired. That’s not really too terrible in the grand scheme of things, but if I decided to update, improve, or fix a bug in one of them I’d have to do it in multiple places to keep them in sync. Okay I take the last statement back a little. That is terrible.

Now that we’ve determined some things wrong and a few things right with these methods, let’s take a look at what I’ve come up with now.

The new and improved code

Some New Helper Types

First we have defined a Result type enum in it’s most basic form. You can find a few good libraries like this one on the web if you’d like something a little more full featured. This simple one with a few generics meets my needs though.

Next we’ve defined a simple error type that will give us a few more options on top of the errors already returned by HealthKit queries.

Lastly we’ve defined some more concrete Result types for our queries to return. This way the caller of these methods can perform a simple switch to determine the success or failure of the query and respond appropriately. In the successful case they get the array of new samples and in the case of failure an error is passed on to the caller so it can respond appropriately. I’ve also again created type aliases for our external caller results handlers to keep our function signatures tidy.

Let’s move on to the methods themselves.

New Base Query Method

I’ve started with a new 3rd method that serves as a base query generator. This new method holds just about as much of the previously duplicated could as I could get into it. The other two sample queries call this one by passing on their parameters and results handlers. This base query also does the checking for errors reported by HealthKit and passes them off to the completion handler if needed.

The New Query Methods

Finally we have our new methods for the query factory. These methods build the base query and give it a completion handler that determines the results of the query and passes it on to the original caller. The completion handlers these two methods provide either pass on the reported HealthKit error or make sure the samples can be typecast appropriately and that we didn’t get an empty sample array back. In this case an error indicating there were no samples returned is passed on to the caller. They return either of those two cases using my spiffy new Result types, greatly simplifying things at the original call sight.

At first glance the method signatures to these two new methods may look a little wordier and convoluted than the originals, but that’s only here at the definition. At the call sight they look almost magical to me. Here’s what you get when accepting Xcode’s autocomplete. I did add line breaks for a better image.

Image for post
Image for post

Here it is in it’s simplest form using the default parameters and with the result handler expanded for clarity.

Image for post
Image for post

The parameter types combine with the labels to make these methods easy to parse and tell what they do. Inside my results handler I can perform a simple switch to determine the appropriate course of action. I’d like to come up with a better label for the limitingResultsTo parameter, but I’m currently stumped for something simpler that conveys the same meaning. It doesn’t hurt that most of my calls to these methods use the variant leveraging the default parameters and I rarely see it. Overall this feels like modern Swift to me and I’m quite satisfied with it. Now I just need to finish the rest of my framework like this and I’ll have a nice API that’ll be a joy to work with.

Do you see anything I could do better or have other suggestions? If you have any other questions or comments feel free to send feedback or thoughts to me on Twitter or Micro.blog.

Originally published at vichudson1.micro.blog on May 26, 2018.

Written by

Code Poet! @WaterRower enthusiast! Making perpetual betas @HealthUpDisplay & @MowingMeterApp. ⅓ of @BubbleSortShow, @pocketsizedpod & host of @AppStoryPodcast.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store