·5 min read

Exploring HealthKit: Working with State of Mind APIs

While I have been working on a lot of apps this summer, the one that I am most excited about is Arising, a mood and emotion tracker based on the new State of Mind APIs in HealthKit.

State of Mind in the Health app helps us to reflect on our current emotions that we are feeling, and our mood for the overall day. I dislike that we can log only one mood per day as if it is constant throughout, but we all know that change is the only constant.

According to the dictionary, emotion is a strong feeling deriving from one's circumstances, mood, or relationships with others. So, we can log such feelings multiple times per day. On the other hand, mood is a temporary state of mind or feeling. As I said earlier, it is a limitation that we can only log one mood per day.

And according to the Health team, the State of Mind APIs are designed in close collaboration with the Emotion Science experts. It has 4 parameters:

Kind

It is an enumeration that helps you provide the context of the feeling.

@available(iOS 18.0, *)
public enum Kind : Int, @unchecked Sendable {
  case momentaryEmotion = 1
  case dailyMood = 2
}

It has two cases:

  • dailyMood: As the name suggests, the kind of state over the day,
  • momentaryEmotion: The kind of state of how somebody feels in the moment.

Valence and ValenceClassification

It is a Double value to meaure someone’s feelings on a scale of -1.0 to 1.0. This value is what is represented by the slider on the Health app with the beautiful animations that goes from “Very Unplesant” to “Neutral” to “Very Pleasant”.

While valence provides with a value, there is an enumeration ValenceClassification that provides the cases of the different state of feeling. It ranges from "very unpleasant" to "very pleasant" with seven levels that you have seen in the Health app:

@available(iOS 18.0, *)
public enum ValenceClassification : Int, @unchecked Sendable {
  case veryUnpleasant = 1
  case unpleasant = 2
  case slightlyUnpleasant = 3
  case neutral = 4
  case slightlyPleasant = 5
  case pleasant = 6
  case veryPleasant = 7
}

What is important to note is that while the enum uses integer values internally, it is typically initialized with a Double value ranging from -1.0 to 1.0:

init?(valence: Double)

You will probably need the name, so let's make it conform to CustomStringConvertible:

extension HKStateOfMind.ValenceClassification: @retroactive CustomStringConvertible {
  public var description: String {
    switch self {
      case .veryUnpleasant: "Very Unpleasant"
      case .unpleasant: "Unpleasant"
      case .slightlyUnpleasant: "Slightly Unpleasant"
      case .neutral: "Neutral"
      case .slightlyPleasant: "Slightly Pleasant"
      case .pleasant: "Pleasant"
      case .veryPleasant: "Very Pleasant"
      @unknown default: "Neautral"
    }
  }
}

Labels

It is the enumeration with the cases about how someone feels. For example, amused, content, indifferent, peaceful, etc. It has numerous cases, a total of 38 at the time of writing this post:

@available(iOS 18.0, *)
public enum Label: Int, @unchecked Sendable {
  case amazed = 1
  case amused = 2
  case angry = 3
  case anxious = 4
  case ashamed = 5
  case brave = 6
  case calm = 7
  case content = 8
  case disappointed = 9
  case discouraged = 10
  case disgusted = 11
  case embarrassed = 12
  case excited = 13
  case frustrated = 14
  case grateful = 15
  case guilty = 16
  case happy = 17
  case hopeless = 18
  case irritated = 19
  case jealous = 20
  case joyful = 21
  case lonely = 22
  case passionate = 23
  case peaceful = 24
  case proud = 25
  case relieved = 26
  case sad = 27
  case scared = 28
  case stressed = 29
  case surprised = 30
  case worried = 31
  case annoyed = 32
  case confident = 33
  case drained = 34
  case hopeful = 35
  case indifferent = 36
  case overwhelmed = 37
  case satisfied = 38
}

As they are integer values, you probably will need to have the names for each of the label. Here is the extension on HKStateOfMind.Label that conforms to CaseIterable:

extension HKStateOfMind.Label: @retroactive CaseIterable, @retroactive CustomStringConvertible {
  public var description: String {
    switch self {
      case .amazed: "Amazed"
      case .amused: "Amused"
      case .angry: "Angry"
      case .anxious: "Anxious"
      case .ashamed: "Ashamed"
      case .brave: "Brave"
      case .calm: "Calm"
      case .content: "Content"
      case .disappointed: "Disappointed"
      case .discouraged: "Discouraged"
      case .disgusted: "Disgusted"
      case .embarrassed: "Embarrassed"
      case .excited: "Excited"
      case .frustrated: "Frustrated"
      case .grateful: "Grateful"
      case .guilty: "Guilty"
      case .happy: "Happy"
      case .hopeless: "Hopeless"
      case .irritated: "Irritated"
      case .jealous: "Jealous"
      case .joyful: "Joyful"
      case .lonely: "Lonely"
      case .passionate: "Passionate"
      case .peaceful: "Peaceful"
      case .proud: "Proud"
      case .relieved: "Relieved"
      case .sad: "Sad"
      case .scared: "Scared"
      case .stressed: "Stressed"
      case .surprised: "Surprised"
      case .worried: "Worried"
      case .annoyed: "Annoyed"
      case .confident: "Confident"
      case .drained: "Drained"
      case .hopeful: "Hopeful"
      case .indifferent: "Indifferent"
      case .overwhelmed: "Overwhelmed"
      case .satisfied: "Satisfied"
      @unknown default: "Unknown"
    }
  }
 
  static func fromIntegerValue(_ value: Int) -> HKStateOfMind.Label? {
    HKStateOfMind.Label(rawValue: value)
  }
 
  public static var allCases: [HKStateOfMind.Label] {
    **[.amazed, .amused, .angry, .anxious, .ashamed,](https://x.com/rudrankriyam)**
 
. and let's chat about it!

Post Topics

Explore more in these categories:

Related Articles

Exploring Stream's Video SDK: Creating a WWDC Watch Party App

Build a WWDC 2024 Watch Party App using Stream's Video SDK. Implement video playback, calling features, and synchronize playback for seamless group viewing. Dive into Stream's powerful tools to create interactive experiences for Apple developers and elevate your WWDC experience.

Exploring Claude: 3.7 Sonnet iOS Development

Explore the capabilities of Claude 3.7 Sonnet in iOS development, featuring improved code refactoring, SwiftUI integration, and efficient file handling. Learn how this AI model streamlines development workflows and handles complex coding tasks with remarkable accuracy and speed.