<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Amy is a cute iOS Developer</title>
  <subtitle>A girl on the internet, writing, thinking, creating. She often travels the world looking for adventure and excitement.</subtitle>
  <link href="https://cuteios.dev/feed.xml" rel="self" type="application/atom+xml"/>
  <link href="https://cuteios.dev/" rel="alternate" type="text/html"/>
  <id>https://cuteios.dev/feed.xml</id>
  <updated>2026-04-15T00:00:00Z</updated>
  
  <entry>
    <title type="html">The trait of a good look</title>
    <link href="https://cuteios.dev/2026/04/15/previews/" rel="alternate" type="text/html" title="The trait of a good look"/>
    <published>2026-04-15T00:00:00Z</published>
    <updated>2026-04-15T00:00:00Z</updated>
    <id>https://cuteios.dev/2026/04/15/previews/</id>
    <content type="html" xml:base="https://cuteios.dev/2026/04/15/previews/">&lt;p&gt;It&#39;s always important to have the right style in any look you go for. The right background. The right shadow. The right fit. The right feel. But by default, any use of a SwiftUI preview lacks all of these. It&#39;s just the view, there without adornment for the world to see. So how can these be improved and built upon?&lt;/p&gt;
&lt;p&gt;The answer to that is the use of traits and specifically &lt;a href=&quot;https://developer.apple.com/documentation/DeveloperToolsSupport/PreviewTrait&quot;&gt;PreviewTrait&lt;/a&gt;. So let&#39;s unpack things a bit.&lt;/p&gt;
&lt;h2&gt;PreviewModifier&lt;/h2&gt;
&lt;p&gt;The first step is to create a modifier that will provide the look and style of the preview. It acts in the same way as &lt;a href=&quot;https://developer.apple.com/documentation/swiftui/viewmodifier&quot;&gt;ViewModifier&lt;/a&gt; that can be used on a View, but has the ability to also provide a &lt;a href=&quot;https://developer.apple.com/documentation/SwiftUI/PreviewModifier/context&quot;&gt;Context&lt;/a&gt;. The context is what allows you to provide extra data such as setting up a database or creating appropriate mocks for the view.&lt;/p&gt;
&lt;h3&gt;Consider a spherical modifier in a vacuum&lt;/h3&gt;
&lt;p&gt;By default, the definition of &lt;a href=&quot;https://developer.apple.com/documentation/swiftui/previewmodifier&quot;&gt;PreviewModifier&lt;/a&gt; will define an associated type for Context as Void. This means that the modifier is just providing a look but avoiding the feel.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;public struct BlackBackgroundModifier: PreviewModifier {
  public func body(content: Content, context: Void) -&amp;gt; some View {
    content
      .background(Color.black)
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As with &lt;a href=&quot;https://developer.apple.com/documentation/swiftui/viewmodifier&quot;&gt;ViewModifier&lt;/a&gt; it is typical to provide a convenience function for it so that it can be used. This would be defined like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;public extension PreviewTrait where T == Preview.ViewTraits {
  static var blackBackground: Self = .modifier(BlackBackgroundModifier()) 
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To make use of this new trait, we provide it when defining the &lt;a href=&quot;https://developer.apple.com/documentation/SwiftUI/Preview(_:traits:_:body:)&quot;&gt;Preview&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;#Preview(traits: .blackBackground) {
  YourAmazingView()
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Giving it all a bit of love and feeling&lt;/h3&gt;
&lt;p&gt;A reference is all good and useful, but the view doesn&#39;t feel alive unless it has the data it usually expects when it exists within your app. A typical approach here is when using &lt;a href=&quot;https://developer.apple.com/documentation/swiftdata&quot;&gt;SwiftData&lt;/a&gt; you can provide the Context as a &lt;a href=&quot;https://developer.apple.com/documentation/swiftdata/modelcontainer&quot;&gt;ModelContainer&lt;/a&gt;. This is the example that is seen everywhere online, but to be honest it can be any type you want. The idea is that the Context gets created once and then it is reused throughout the Canvas lifecycle showing the Preview(s).&lt;/p&gt;
&lt;p&gt;So lets work through this example. It sets up a model container and provides it to the view. You can get access to the Context from within the &lt;a href=&quot;https://developer.apple.com/documentation/swiftui/previewmodifier/body(content:context:)&quot;&gt;body&lt;/a&gt; function and then apply it to the view.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct PreviewSampleData: PreviewModifier {
  static func makeSharedContext() throws -&amp;gt; ModelContainer {
    let config = ModelConfiguration(
      isStoredInMemoryOnly: true
    )
    
    do {
      let container = try ModelContainer(
        for: FeelGoodJournalEntry.self,
        configurations: config
      )
      try addSampleData(to: container)
      return container
    } catch {
      fatalError(&amp;quot;Couldn&#39;t create container: &#92;(error.localizedDescription)&amp;quot;)
    }
  }
  
  func body(content: Content, context: ModelContainer) -&amp;gt; some View {
    content.modelContainer(context)
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The sky is the limit&lt;/h2&gt;
&lt;p&gt;So this is a simplified for teaching example of how a &lt;a href=&quot;https://developer.apple.com/documentation/swiftui/previewmodifier&quot;&gt;PreviewModifier&lt;/a&gt; and &lt;a href=&quot;https://developer.apple.com/documentation/DeveloperToolsSupport/PreviewTrait&quot;&gt;PreviewTrait&lt;/a&gt; can be used to provide look and feel to your previews. From here, it&#39;s a matter of exploring and seeing how you can use them to improve the experience of your development within Xcode.&lt;/p&gt;
</content>
    <summary>Make sure your previews look their best by implementing `PreviewModifier` and `PreviewTrait`</summary>
  </entry>
  
  <entry>
    <title type="html">One thing leads to another</title>
    <link href="https://cuteios.dev/2026/04/06/migrations/" rel="alternate" type="text/html" title="One thing leads to another"/>
    <published>2026-04-06T00:00:00Z</published>
    <updated>2026-04-06T00:00:00Z</updated>
    <id>https://cuteios.dev/2026/04/06/migrations/</id>
    <content type="html" xml:base="https://cuteios.dev/2026/04/06/migrations/">&lt;h2&gt;A tale as old as time&lt;/h2&gt;
&lt;p&gt;Since the introduction of iPhone SDK 3.0 developers have been dealing with data migrations on mobile devices. As mobile apps grow, their data requirements change alongside them and being on top of migrations is a black art that even the most current LLM has difficulty with.&lt;/p&gt;
&lt;h2&gt;The reliance on magic&lt;/h2&gt;
&lt;p&gt;When SwiftData was introduced in 2023, it brought with it a new approach to migrations being &lt;a href=&quot;https://developer.apple.com/documentation/swiftdata/schemamigrationplan&quot;&gt;SchemaMigrationPlan&lt;/a&gt; that allows for programatically migrating between versions. Those who have dealt in the dark arts of CoreData migrations know that there exists &lt;a href=&quot;https://www.objc.io/issues/4-core-data/core-data-migration/&quot;&gt;blog posts&lt;/a&gt; and also official &lt;a href=&quot;https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreDataVersioning/Articles/vmLightweightMigration.html&quot;&gt;apple documentation&lt;/a&gt; on the matter. The difference being that with SwiftData, the approach is a lot more approachable.&lt;/p&gt;
&lt;p&gt;Where as CoreData relied on mapping files to handle migrations, in SwiftData there is a definite gotcha there where the often used examples say to just put the &lt;a href=&quot;https://developer.apple.com/documentation/swiftdata/model()&quot;&gt;@Model&lt;/a&gt; macro everywhere with abandon in order to get the magic. This works great if you know that you&#39;ll only ever do lightweight migrations, but if you need to change anything more substantially, this approach relies to much on magic.&lt;/p&gt;
&lt;p&gt;Adoption of &lt;a href=&quot;https://developer.apple.com/documentation/swiftdata/versionedschema&quot;&gt;VersionedSchema&lt;/a&gt; is a way to avoid but if you&#39;re app is already in the wild then you need to take a few extra steps to bring everything into line with versioned schemas.&lt;/p&gt;
&lt;h2&gt;Defining the schemas&lt;/h2&gt;
&lt;p&gt;The first step is to define all your existing SwiftData models in a VersionedSchema. This can look like the following. The important part to remember is that this first version should match your existing models exactly.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;public struct Version1: VersionedSchema {
  public static let models: [any PersistentModel.Type] = [
	Version1.One.self,
	Version1.Two.self,
	Version1.Three.self,
  ]

  public static let versionIdentifier = Schema.Version(1, 0, 0)

  public init() {

  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By making use of the &lt;code&gt;Version1&lt;/code&gt; struct you can namespace your types. A public typealias will then allow for continuing to use the existing types without code change. This is also a good chance to define &lt;code&gt;CurrentVersion&lt;/code&gt; as a type so that when you move between versions, the references in your code don&#39;t require change.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;public typealias CurrentVersion = Version1

public typealias One = CurrentVersion.One
public typealias Two = CurrentVersion.Two
public typealias Three = CurrentVersion.Three
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When creating your model container, you can then make use of the new VersionedSchema definition.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let schema = Schema(versionedSchema: CurrentVersion.self)

let modelConfiguration = ModelConfiguration(
  schema: schema,
  isStoredInMemoryOnly: false,
  cloudKitDatabase: .private(&amp;quot;iCloud.your.app.data&amp;quot;)
)

let container = try ModelContainer(
  for: schema,
  configurations: modelConfiguration
)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Not so fast&lt;/h3&gt;
&lt;p&gt;If you are going from a non versioned schema to a versioned schema, you will unfortunately hit an error when creating the model container &lt;code&gt;&amp;quot;Cannot use staged migration with an unknown model version.&amp;quot;&lt;/code&gt;. This error is unfortunately not well documented, but there is a common work around you can use. The trick is to explicitly load the &lt;code&gt;Version1&lt;/code&gt; schema first and then continue with any other migrations.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;do
{
  return try liveModelContainer()
} catch SwiftDataError.loadIssueModelContainer {
  do {
    let legacySchema = Schema(versionedSchema: Version1.self)
    let legacyModelConfiguration = ModelConfiguration(
      schema: legacySchema,
      isStoredInMemoryOnly: false,
      cloudKitDatabase: .none
    )
    let legacyContainer = try ModelContainer(
      for: legacySchema,
      configurations: [legacyModelConfiguration]
    )

    try legacyContainer.mainContext.save()

    return try liveModelContainer()
  } catch {
    // Log and handle any other errors here
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point, you should be able to successfully load your data as a versioned schema without any issues.&lt;/p&gt;
&lt;h2&gt;And on and on and on and on&lt;/h2&gt;
&lt;p&gt;As apps grow in size, you will want to define a &lt;a href=&quot;https://developer.apple.com/documentation/swiftdata/schemamigrationplan&quot;&gt;SchemaMigrationPlan&lt;/a&gt; to allow you to constantly grow your apps data requirements.&lt;/p&gt;
&lt;p&gt;As with anything there are a few caveats when using a schema migration plan. The majority of things will hopefully be covered by a &lt;a href=&quot;https://developer.apple.com/documentation/swiftdata/migrationstage/lightweight(fromversion:toversion:)&quot;&gt;.lightweight&lt;/a&gt; &lt;a href=&quot;https://developer.apple.com/documentation/swiftdata/migrationstage&quot;&gt;MigrationStage&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When you need to start modifying your data or changing it between app versions, this can get tricky and you will need to make use of a &lt;a href=&quot;https://developer.apple.com/documentation/swiftdata/migrationstage/custom(fromversion:toversion:willmigrate:didmigrate:)&quot;&gt;.custom&lt;/a&gt; migration stage.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;public class AppMigrationPlan: SchemaMigrationPlan {
  public static var schemas: [any VersionedSchema.Type] {
    [
      Version1.self,
      Version2.self,
    ]
  }

  public static var stages: [MigrationStage] {
    [
      migrateV1toV2,
    ]
  }

  static let migrateV1toV2: MigrationStage = .custom(
	fromVersion: Version1.self,
	toVersion: Version2.self
  ) { context in
    // Your Version1 models are available here
  } didMigrate: { context in
    // Your Version2 models are available here
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The important thing to remember is that you can&#39;t access anything from your old schema version inside of the &lt;code&gt;didMigrate&lt;/code&gt; closure as the schema has already changed at that point. So if you are wanting to move data from &lt;code&gt;var foo&lt;/code&gt; to a combination of &lt;code&gt;var baz&lt;/code&gt; and &lt;code&gt;var blorp&lt;/code&gt; then you will need to store this data as part of the &lt;code&gt;willMigrate&lt;/code&gt; closure so that it is retained. You can then set it on the corresponding versioned model in &lt;code&gt;didMigrate&lt;/code&gt; and save the changes.&lt;/p&gt;
&lt;p&gt;There&#39;s a lot of hand waving here, but that&#39;s intentional. The specific requirements of migrations aren&#39;t what&#39;s important. The important thing is to get your app into a versioned schema and then start writing the migrations.&lt;/p&gt;
</content>
    <summary>As your app grows make sure your data comes along for the ride</summary>
  </entry>
  
  <entry>
    <title type="html">The music we share with friends.</title>
    <link href="https://cuteios.dev/2024/03/09/shared-music/" rel="alternate" type="text/html" title="The music we share with friends."/>
    <published>2024-03-09T00:00:00Z</published>
    <updated>2024-03-09T00:00:00Z</updated>
    <id>https://cuteios.dev/2024/03/09/shared-music/</id>
    <content type="html" xml:base="https://cuteios.dev/2024/03/09/shared-music/">&lt;h3&gt;It was a dark and stormy stardate 57162.3&lt;/h3&gt;
&lt;p&gt;The girl slumped down in her office chair. The meeting was over and once again it had been one of those meetings. But that&#39;s okay, she knew how to deal with them and how to regain control of her emotions afterwards. One of the group chats she was in served as a great outlet stress and they were all her chosen family. It was a safe place for all of them to vent about what&#39;s going on in life. The second thing she needed was some music.&lt;/p&gt;
&lt;p&gt;She queued something up on her HomePod&#39;s and closed her eyes waiting for the bass to drop and the stress to start slowly leaving her body as the music took hold. Opening her eyes again, she moved to the next step in the ritual. She wanted to share the music she was listening to with the group as it was relevant to her outpouring of emotions and regaining control.&lt;/p&gt;
&lt;p&gt;This time though, she was confronted by issues. She had to go looking for the song in music.app and then navigate to the share sheet so that she could simply get the URL for the track she wanted to share. It was all too much and she threw up her arms in frustration, letting out a high pitched wail of frustration. There had to be a better way of handling this situation.&lt;/p&gt;
&lt;h3&gt;File -&amp;gt; New Project&lt;/h3&gt;
&lt;p&gt;Once the inevitable break down had subsided, the girl was spurred into action. She had a problem to solve and would not be satisfied until a situation had presented itself. There had to be an easier way to share the music with her friends. Her mental health depended on it. Well, maybe not depend on but it was a distraction.&lt;/p&gt;
&lt;p&gt;Breaking apart the task, there were a few things that needed to be accomplished so she could start sharing the music she listened to with her friends.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Obtaining permission&lt;/li&gt;
&lt;li&gt;Finding out the playback history&lt;/li&gt;
&lt;li&gt;Creating a UI&lt;/li&gt;
&lt;li&gt;Sharing the track&lt;/li&gt;
&lt;li&gt;Access from anywhere&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A plan set out, it was now time for the girl to get to work.&lt;/p&gt;
&lt;h3&gt;Setting up the project&lt;/h3&gt;
&lt;p&gt;Surprisingly this turned out to be the most complex of the issues to address. The girl had to set up a complete project in the &lt;a href=&quot;https://developer.apple.com/account&quot;&gt;Apple Developer portal&lt;/a&gt; in order to get access to MediaKit from within her application. While impressed by the structure of the MusicKit API, she was caught out by how it interacted with lower level parts of apples platforms. Like &lt;a href=&quot;https://developer.apple.com/documentation/weatherkit/&quot;&gt;WeatherKit&lt;/a&gt; and &lt;a href=&quot;&quot;&gt;ShazamKit&lt;/a&gt; the &lt;a href=&quot;&quot;&gt;MusicKit&lt;/a&gt; framework made use of a system daemon that handled things such as caching and authentication for all apps making use of the framework. She let a relaxed smile appear on her face having realised this. The extra steps involved were there for a purpose and meant that the task of having her app remain a good citizen when using the MusicKit API was handled by the platform. She noted down the &lt;a href=&quot;https://developer.apple.com/documentation/musickit/using_musickit_to_integrate_with_apple_music&quot;&gt;documentation link&lt;/a&gt; in her notebook that constantly sat open by her side (what girl doesn&#39;t have a stack of notebooks just sitting around with random things contained therein?)&lt;/p&gt;
&lt;h3&gt;Obtaining permission&lt;/h3&gt;
&lt;p&gt;A grin crept across the girls face. She had the project set up. She was now ready to get going with the fun part of the project. She would be able to write some code. There would be unit tests, there would be comments. The structure would flow like a well choreographed dance number. Grace, elegance, fluidity. All the things that reflect the girls nature and attitude towards life. Everything about her gets poured out into the work she does.&lt;/p&gt;
&lt;p&gt;First up, she needed to ask the for the users permission to access the music library on behalf of the user. This is always an important step as accessing user data without permission is an invasion of the user privacy. She remembered the stories about peoples data being harvested and sold and she didn&#39;t want anything about that. Thankfully, there was a type in MusicKit helpfully labeled as &lt;a href=&quot;https://developer.apple.com/documentation/musickit/musicauthorization&quot;&gt;MusicAuthorization&lt;/a&gt; that contained exactly what she needed.&lt;/p&gt;
&lt;p&gt;While reading the documentation, she noticed that there needed to be a property list value added to the &lt;code&gt;info.plist&lt;/code&gt; file labeled &lt;a href=&quot;https://developer.apple.com/documentation/bundleresources/information_property_list/nsapplemusicusagedescription&quot;&gt;NSAppleMusicUsageDescription&lt;/a&gt;. When requesting authorisation, the text associated with this value is presented to the user. It makes clear what the consent is being requested and why it is being requested.&lt;/p&gt;
&lt;p&gt;Well, she thought to herself, that&#39;s another point for relying on the platform to take care of the heavy lifting. She doesn&#39;t need to make her own implementation. Let&#39;s test this out she sang to herself and proceeded to place some code into the view model (structure is important and all business logic gets separated out from the view).&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;let status = switch await MusicAuthorization.currentStatus {
case .authorized:
  .authorized
case .restricted:
  .restricted
case .denied, .notDetermined:
  MusicAuthorization.request()
@unknown default:
  break
}

if case .authorized = status || case .restricted = status {
  // Handle request here
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On the first run, she let out a cheer as the prompt appeared to ask for consent. Forward momentum is always a good thing.&lt;/p&gt;
&lt;h3&gt;Finding out the playback history&lt;/h3&gt;
&lt;p&gt;Knowing that she could access the music library she could now ask questions of it. These questions were done using a request / response handshake. Thankfully she could make use of the generic types to create a specific query and get the response crafted to her liking. This was a powerful side of the swift programming language that she always enjoyed using. &lt;a href=&quot;https://developer.apple.com/documentation/musickit/musicrecentlyplayedrequest&quot;&gt;MusicRecentlyPlayedRequest&lt;/a&gt; was the type that she needed for the request and looking at it, she could see that it was generic over the type of &lt;a href=&quot;https://developer.apple.com/documentation/musickit/musicitem/&quot;&gt;MusicItem&lt;/a&gt; that included things like &lt;a href=&quot;https://developer.apple.com/documentation/musickit/album&quot;&gt;Album&lt;/a&gt;, &lt;a href=&quot;https://developer.apple.com/documentation/musickit/playlist&quot;&gt;Playlist&lt;/a&gt;, &lt;a href=&quot;https://developer.apple.com/documentation/musickit/song&quot;&gt;Song&lt;/a&gt; and &lt;a href=&quot;https://developer.apple.com/documentation/musickit/track&quot;&gt;Track&lt;/a&gt; that were perfect for her needs. She could easily customise the apps behaviour to show any of these or even more as long as it conformed to the correct protocol. Another point to well designed API&#39;s.&lt;/p&gt;
&lt;p&gt;With the request created, she then needed to get a response. There was a corresponding response to the request available to her that she could make use of. This was &lt;a href=&quot;https://developer.apple.com/documentation/musickit/musicrecentlyplayedresponse&quot;&gt;MusicRecentlyPlayedResponse&lt;/a&gt;. So it was now time for the girl to get to writing some more code.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;var request = MusicRecentlyPlayedRequest&amp;lt;Track&amp;gt;()
request.limit = 1

let response = try await request.response()

guard let track = response.items.first else {
  throw Errors.noRecentlyPlayed
}

// Do something with the track data returned
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Creating a UI&lt;/h3&gt;
&lt;p&gt;With the data now flowing to her app, it was time to create the UI. As the girl had selected a multiplatform app when creating the project, there was only one approach to take for the UI and that was to use &lt;a href=&quot;https://developer.apple.com/documentation/swiftui&quot;&gt;SwiftUI&lt;/a&gt; as it meant she could be expressive in how she built the UI and know that the platform running the app would happily translate the UI to something appropriate for its conventions and behaviours. Gone were the days having to splatter &lt;code&gt;#if os(macOS)&lt;/code&gt; all throughout the codebase and have multiple targets each with their own quirks and conventions.&lt;/p&gt;
&lt;p&gt;To get started, the girl envisioned a simple UI. One that started by showing information over delight. She would move onto that at some stage, but for now she was content on getting things on the screen first.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;VStack(alignment: .center, spacing: 12) {
  AsyncImage(url: song.imageURL) { image in
    image
      .resizable()
      .frame(width: 400, height: 400)
  } placeholder: {
    ProgressView()
      .progressViewStyle(.circular)
  }
  Text(song.title)
  Text(song.artist)
  HStack {
    if let shareURL = song.shareURL {
      ShareLink(item: shareURL)
    }
    Button(&amp;quot;Copy&amp;quot;, systemImage: &amp;quot;doc.on.doc&amp;quot;) {
      viewModel.copyToPasteboard()
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Sharing the track&lt;/h3&gt;
&lt;p&gt;It was here that the girl was faced with a choice. Did she want to implement the standard platform behaviour of a &lt;a href=&quot;https://developer.apple.com/design/human-interface-guidelines/collaboration-and-sharing/&quot;&gt;Share Sheet&lt;/a&gt; that provided the most extensible way of getting the information about the album / track / song / playlist to others? Did she want to just copy the URL to the clipboard so that she could paste it where she wanted? A lot of her current frustration for building the new app stemmed from the lack of discoverability around the share sheet in Apple&#39;s Music app and how it introduced many extra steps to completing the task at hand. She also understood that a URL often lacks the extra information required when sharing. In the end, she needed to provide both options to the users. The first option, using a share sheet, could be achieved by using the &lt;a href=&quot;https://developer.apple.com/documentation/SwiftUI/ShareLink&quot;&gt;ShareLink&lt;/a&gt; type in SwiftUI and letting the platform take care of the nuance around presentation.&lt;/p&gt;
&lt;p&gt;The second option required a bit more nuance as &lt;a href=&quot;https://developer.apple.com/documentation/appkit/nspasteboard/&quot;&gt;NSPasteboard&lt;/a&gt; and &lt;a href=&quot;https://developer.apple.com/documentation/uikit/uipasteboard/&quot;&gt;UIPasteboard&lt;/a&gt; had their own quirks and the girl needed to resort to having different behaviour between. Thankfully the differences weren&#39;t substantial. The girl also took note that the pasteboard was for more than just string and binary values. She could be expressive with the data she provided and that would let other apps determine if and how they responded to a paste event. For her app, specifying that the pasteboard was handling a URL was sufficient.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;#if os(macOS)
NSPasteboard.general.setString(url.absoluteString, forType: .URL)
#else
UIPasteboard.general.url = url
#endif
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Access from anywhere&lt;/h3&gt;
&lt;p&gt;At last the girl could get the song she was listening to could be shared easily with her friends. But there were quirks. Apple&#39;s platforms were great for multitasking, but they still needed switching between apps. You could scatter multiple windows over the desktop on macOS but you still had to switch between them. On iOS and iPadOS there was a need to switch between them as well. Thankfully on macOS the problem could be addressed by the use of &lt;a href=&quot;https://developer.apple.com/documentation/swiftui/menubarextra/&quot;&gt;MenuBarExtra&lt;/a&gt; as a scene within the app. On iOS and iPadOS she would need to look for other solutions.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;MenuBarExtra(&amp;quot;Your App Name&amp;quot;, systemImage: &amp;quot;music.note.list&amp;quot;) {
  // UI goes here
}
.menuBarExtraStyle(.window)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Taking it further&lt;/h3&gt;
&lt;p&gt;The girls voice rang out in jubilation. She had a solution to her problem and she was keen to share it with the world at large. Her friends first as they received the test flight link and then she put her mind to releasing the app once feedback had been received. This is where her passion lies, her delight is found. Her voice. Her song.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;narrators note&lt;/strong&gt; app is still being finalised though will be released at some point in the future.&lt;/p&gt;
</content>
    <summary>Having some fun with friends while listening to music</summary>
  </entry>
  
  <entry>
    <title type="html">A Girl and her @ViewBuilder</title>
    <link href="https://cuteios.dev/2024/01/10/viewbuilder/" rel="alternate" type="text/html" title="A Girl and her @ViewBuilder"/>
    <published>2024-01-10T00:00:00Z</published>
    <updated>2024-01-10T00:00:00Z</updated>
    <id>https://cuteios.dev/2024/01/10/viewbuilder/</id>
    <content type="html" xml:base="https://cuteios.dev/2024/01/10/viewbuilder/">&lt;p&gt;&lt;em&gt;&lt;strong&gt;note&lt;/strong&gt;&lt;/em&gt;: the story here is fictional, but it&#39;s an approach I love to take when solving similar problems. Hope you enjoy it and get a good understanding of how make use of &lt;code&gt;@ViewBuilder&lt;/code&gt; in SwiftUI apps.&lt;/p&gt;
&lt;h2&gt;Once upon a time&lt;/h2&gt;
&lt;p&gt;One upon a time, a girl was presented with a task. Refactor this code her manager demanded, another team is wanting to reuse this part of the UI. &amp;quot;Happy to&amp;quot; she responded, knowing that there was no getting out of this work. &#39;Tis much better to build this well and share it around than have many implementations of the same thing with very small differences between them. None of which quite solving the problem. Loading up a &lt;a href=&quot;https://music.apple.com/au/playlist/riot-grrrl-essentials/pl.4ac9566eba234d99971cface91950c1c&quot;&gt;Riot Grrrl&lt;/a&gt; playlist in Apple Music, she pulled down the latest version of the codebase and began to work. The code she found wasn&#39;t the best. If it were, she wouldn&#39;t be doing this task now would she? She had seen this kind of code many times before. A few different components wrapped up in what would colloquially be described as a card. There was a &lt;a href=&quot;https://developer.apple.com/documentation/swiftui/vstack&quot;&gt;VStack&lt;/a&gt; with the different bits and pieces stuck in there along with a fairly standard set of &lt;a href=&quot;https://developer.apple.com/documentation/swiftui/viewmodifier&quot;&gt;view modifiers&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Understanding the requirements&lt;/h2&gt;
&lt;p&gt;There are many approaches the girl could take to solving this problem. One option would be to rename the existing view, expose properties for things like title, image, text and throw it into a shared part of the project. But she knows well and true that will only cause pain down the track. She needs a way to make the content arbitrary while maintaining style and functionality. This will give her the best base component to allow others to build upon.&lt;/p&gt;
&lt;h2&gt;Looking at alternatives&lt;/h2&gt;
&lt;p&gt;In her time working on apps built in SwiftUI the girl knew of a few solutions she could apply to make this all work as she wanted&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;view builders&lt;/li&gt;
&lt;li&gt;view extensions&lt;/li&gt;
&lt;li&gt;view modifiers&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;View Modifiers&lt;/h4&gt;
&lt;p&gt;View modifiers have been around since the start of SwiftUI and have been a long established way of applying a common set of modifications to a view. The girls team has experience with this and she knows there will be little cognitive overhead for them to pick up the preferred way of doing this. So how would this look to her teammates? This is always an important question to ask and so she opened up a &lt;a href=&quot;https://developer.apple.com/swift-playgrounds/&quot;&gt;Swift Playground&lt;/a&gt; (We all remember those things right? More than just for WWDC scholarship applications) and started roughing out what it would be.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;public struct CardModifier: ViewModifier {
  func body(content: Content) -&amp;gt; some View {
    content
      .frame(maxWidth: .infinity, alignment: .leading)
      .fixedSize(horizontal: false, vertical: true)
      .padding(8)
      .background(Color.background)
      .mask(RoundedRectangle(cornerRadius: 8, style: .continuous))
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then it&#39;s usage in a view&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;Text(&amp;quot;Hello World&amp;quot;)
  .modifier(CardModifier())
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But is this as good as it could be? The girl sat there in her chair, one leg tucked under her in a posture that confounds her colleagues and sipped on the tea she had recently poured for herself. A miracle that she remembered to take a break and spend time contemplating next steps. She knew that this would solve a problem, but would it encourage the team to use it and have an understanding of what is being accomplished? She gazed at her Swift Playground a bit more, but was not satisfied she could answer that question in the affirmative. One approach down, on to the next one.&lt;/p&gt;
&lt;h4&gt;View Extensions&lt;/h4&gt;
&lt;p&gt;Knowing that SwiftUI is very idiomatic, the girl started to ponder the question &amp;quot;What if this was an extension on View?&amp;quot;. Thankfully this one could be proven viable or not by a simple addition to her open Swift Playground.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;extension View {
  func displayAsCard() -&amp;gt; some View {
    modifier(CardModifier())
  }  
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This then gave her the freedom to apply it to any view type and have it understandable that the view itself was being displayed as a card. But she knew, even this didn&#39;t have what she was looking for. It was a single change to an existing View in the app but it lacked discoverability and had a high cognitive overhead on her colleagues. She didn&#39;t want to make life more difficult for her friends that she interacted with ever day. Well, there was one who was super annoying but what work environment doesn&#39;t have people like that in them. The girl shuddered and as she was still holding her tea for warmth in both hands took a calming sip of tea. Thankfully, she knew of a solution and where she wanted to go with this bit of work.&lt;/p&gt;
&lt;h4&gt;View Builders&lt;/h4&gt;
&lt;p&gt;Each year the girl spent a good amount of her time travelling the world and speaking with others in the industry. She had to be super careful in this as the environments could very easily be toxic. She was there to learn more about what she loved doing day to day. A repeated theme amongst conversations is how Swift as a language allows for the writing of DSL&#39;s and this was a super powerful technique to use when writing apps with SwiftUI. She had heard of the idea about &lt;a href=&quot;https://docs.swift.org/swift-book/documentation/the-swift-programming-language/advancedoperators/#Result-Builders&quot;&gt;result builders&lt;/a&gt; and their specific application in SwiftUI being &lt;a href=&quot;https://developer.apple.com/documentation/swiftui/viewbuilder&quot;&gt;@ViewBuilder&lt;/a&gt;. Needing a refresher before continuing, she queued up a few WWDC videos on the topics being &lt;a href=&quot;https://developer.apple.com/wwdc21/10253&quot;&gt;Write a DSL in Swift using result builders&lt;/a&gt; and &lt;a href=&quot;https://developer.apple.com/wwdc22/110352&quot;&gt;Embrace Swift generics&lt;/a&gt; that deal with the topic. She couldn&#39;t help but be excited that both presenters in the videos were female. With how much progress had been made in recent years, there was still a long way to go towards gender equality.&lt;/p&gt;
&lt;p&gt;The girl now had the approach she wanted to take sorted out. She fetched yet another cup of tea and got to work on the solution.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct Card&amp;lt;Content: View&amp;gt;: View {
  let configuration: CardViewConfiguration
  let content: Content

  init(configuration: CardViewConfiguration = .default, @ViewBuilder content: () -&amp;gt; Content) {
    self.configuration = configuration
    self.content = content()
  }

  var body: some View {
    content
      .frame(maxWidth: .infinity, alignment: .leading)
      .fixedSize(horizontal: false, vertical: true)
      .padding(configuration.padding)
      .background(configuration.backgroundColor)
      .mask(
        RoundedRectangle(
          cornerRadius: configuration.cornerRadius,
          style: .continuous
        )
      )
  }
}

struct CardConfiguration {

  public let backgroundColor: Color
  public let cornerRadius: CGFloat
  public let padding: CGFloat

  public init(backgroundColor: Color, cornerRadius: CGFloat, padding: CGFloat) {
    self.backgroundColor = backgroundColor
    self.cornerRadius = cornerRadius
    self.padding = padding
  }

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This had the advantage of being usable within the app in a way to simply described what was being created and allowed others to build what they want on top of it.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;Card {
  Text(&amp;quot;Hello World&amp;quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Bringing the team on board&lt;/h2&gt;
&lt;p&gt;Satisfied with how the use of ViewBuilder came out, the next step for the girl was to bring her team onboard with the approach. She could slap together a PR and send it up for others to review, but that wouldn&#39;t achieve much. If others were to start adopting a similar approach in how they wrote views, she would need to give them as much help as possible. This was more than just chatting with other engineers. Now it was time for a checklist. She still had a lot of work to do to ensure adoption by others.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Chat with UX designers about upcoming usages.&lt;/li&gt;
&lt;li&gt;Chat with accessibility experts about how it would look for vision impaired users.&lt;/li&gt;
&lt;li&gt;Inline documentation that covers example usage.&lt;/li&gt;
&lt;li&gt;Brown bag (small talk / meeting at work) covering the usage of &lt;code&gt;@ViewBuilder&lt;/code&gt; in the app and other possibilities for the use of similar DSL&#39;s.&lt;/li&gt;
&lt;li&gt;Work with engineers as they adopt the new UI component and adopted similar patterns in their work.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The girl leaned back in her chair, cup of tea firmly grasped in both hands. It will go unmentioned how many she had consumed throughout this day. She was satisfied that she had met the requirements of the work and the team is now in a better place.&lt;/p&gt;
</content>
    <summary>Making use of ViewBuilder in SwiftUI</summary>
  </entry>
  
  <entry>
    <title type="html">Formatters and Measurements</title>
    <link href="https://cuteios.dev/2024/01/05/formatters/" rel="alternate" type="text/html" title="Formatters and Measurements"/>
    <published>2024-01-05T00:00:00Z</published>
    <updated>2024-01-05T00:00:00Z</updated>
    <id>https://cuteios.dev/2024/01/05/formatters/</id>
    <content type="html" xml:base="https://cuteios.dev/2024/01/05/formatters/">&lt;h2&gt;Why data is important&lt;/h2&gt;
&lt;p&gt;Data is what makes apps viable. It is what drives the user interactions and informs them of what&#39;s going on. While some apps use data in the form of text, there are other apps that use very fine grained measurements and need to present these in ways that are appropriate for the user.&lt;/p&gt;
&lt;h2&gt;Respecting the users locale&lt;/h2&gt;
&lt;p&gt;When dealing with data relating to measurements we want to be respectful of the users locale and language settings. If we have a value that has been recorded as meters per second and the users default measurement for speed is miles per hour, we want to respect that when we display the value to the user. Similarly if a temperature measurement is in degrees Kelvin, we want to format that in the users default value such as Celsius or Fahrenheit.&lt;/p&gt;
&lt;h2&gt;Creating a custom Formatter&lt;/h2&gt;
&lt;p&gt;A lot of formatters already exist and are provided by as part of the respective platforms and should be preferred over a custom implementation of &lt;a href=&quot;https://developer.apple.com/documentation/foundation/formatter/&quot;&gt;Formatter&lt;/a&gt;. There is also &lt;a href=&quot;https://developer.apple.com/documentation/foundation/data_formatting/building_a_localized_food-ordering_app&quot;&gt;sample code&lt;/a&gt; from Apple which demonstrates the use of formatters in an app.&lt;/p&gt;
&lt;p&gt;Though there are times when we want to take a string such as &amp;quot;ABCD1234EFGH5678&amp;quot; and turn it into something like &amp;quot;ABCD-1234-EFGH-5678&amp;quot; which is then displayed to the user. To do this, we want to create a custom formatter. This sounds complex, but it is as a straight forward and the good thing is that the implementation can be unit tested.&lt;/p&gt;
&lt;h3&gt;Define the subclass&lt;/h3&gt;
&lt;p&gt;To get started, define a new value type such as the following.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;class SuperAwesomeCustomFormatter {

}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Create the implementation&lt;/h3&gt;
&lt;p&gt;After defining the class, we can build out the implementation. The amazing thing about how this protocol is defined is that it doesn&#39;t case what the value being passed in is. It is the responsibility of the formatter to determine if it knows how to provide an appropriate String as a result.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;extension SuperAwesomeCustomFormatter: Formatter {

  override func string(for obj: Any?) -&amp;gt; String? {
    /* 
    super secret custom implementation goes here okay, 
    just make sure you return an optional String value.
    The actual implementation is left as an exercise
    for the reader to look at.
    */
    nil
  }

}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.apple.com/documentation/foundation/formatter&quot;&gt;Formatter&lt;/a&gt; class provides the definition &lt;a href=&quot;https://developer.apple.com/documentation/foundation/formatter/1415993-string&quot;&gt;string(for:)&lt;/a&gt; as well as &lt;a href=&quot;https://developer.apple.com/documentation/foundation/formatter/1409478-attributedstring&quot;&gt;attributedString(for:withDefaultAttributes:)&lt;/a&gt; and &lt;a href=&quot;https://developer.apple.com/documentation/foundation/formatter/1416333-editingstring&quot;&gt;editingString(for:)&lt;/a&gt;. This makes the Formatter subclass super powerful and adaptable to the use case. Do take note of the default behaviour discussion in the apple documentation if you are overriding these values.&lt;/p&gt;
&lt;h3&gt;Write some unit tests&lt;/h3&gt;
&lt;p&gt;As we are dealing with formatting strings we want to make sure that it does what is expected. So for this we write some unit tests. These tests can be as simple or as complex as you want.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;class SuperAwesomeCustomFormatterTests: XCTestCase {

  func testFormatsString() {
    let testSubject = SuperAwesomeCustomFormatter()
    let expected = &amp;quot;1234-ABCD-4567-EFGH&amp;quot;
    let result = testSubject.string(for: &amp;quot;1234ABCD4567EFGH&amp;quot;)
		
    XCTAssertEqual(expected, result)
  }

}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Showing formatted values&lt;/h2&gt;
&lt;p&gt;A lot of SwiftUI types work with a formatter such as &lt;a href=&quot;https://developer.apple.com/documentation/swiftui/text/init(_:formatter:)-2he2c&quot;&gt;Text&lt;/a&gt; and &lt;a href=&quot;https://developer.apple.com/documentation/swiftui/textfield/init(_:value:formatter:)-4013v&quot;&gt;TextField&lt;/a&gt;. This is demonstrated by a super simple view like the following which presents a TextField and uses an appropriate custom formatter for the value.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;struct ContentView: View {

  @State var superAwesomeString: String = &amp;quot;&amp;quot;

  var body: some View {
    VStack {
      TextField(
        &amp;quot;Super Awesome Value&amp;quot;,
        value: $superAwesomeString,
        formatter: .superAwesomeFormatter
      )
    }
    .padding()
  }

}

extension Formatter {

  static var superAwesomeFormatter: Formatter = {
    SuperAwesomeFormatter()
  }()

}
&lt;/code&gt;&lt;/pre&gt;
</content>
    <summary>Using custom formatters in SwiftUI</summary>
  </entry>
  
  <entry>
    <title type="html">WWDC 23 Wishlist</title>
    <link href="https://cuteios.dev/2023/04/11/wwdc-wishlist/" rel="alternate" type="text/html" title="WWDC 23 Wishlist"/>
    <published>2023-04-11T00:00:00Z</published>
    <updated>2023-04-11T00:00:00Z</updated>
    <id>https://cuteios.dev/2023/04/11/wwdc-wishlist/</id>
    <content type="html" xml:base="https://cuteios.dev/2023/04/11/wwdc-wishlist/">&lt;p&gt;Each year as it gets close to &lt;a href=&quot;https://developer.apple.com/wwdc&quot;&gt;wwdc&lt;/a&gt; developers love to speculate as to what they would love for Apple to release at their annual conference. I&#39;ll not get in to the out there rumours (mixed reality headset being the exception) but rather focusing on what would make my live a lot easier as an engineer.&lt;/p&gt;
&lt;h2&gt;CoreData uplift&lt;/h2&gt;
&lt;p&gt;We have seen how amazingly flexible Swift as a language is, particularly how easy it is to create a DSL using result builders is. Having a database persistence layer available that feels native to Swift apps would be a huge win.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Modern Swift API&lt;/li&gt;
&lt;li&gt;Generated classes use swift types (not NSSet)&lt;/li&gt;
&lt;li&gt;Thread and type safety&lt;/li&gt;
&lt;li&gt;async / await&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;SwiftUI Previews from packages&lt;/h2&gt;
&lt;p&gt;This one has plagued developers for a long time. If you have a SwiftUI view defined in an SPM package along with a preview for the view, you can&#39;t use the canvas if your target is set to the main app. Yes you can change the target to be just the SPM package as a work around but that is really an unplesant experience for developers.&lt;/p&gt;
&lt;h2&gt;SwiftUI Map enhancements&lt;/h2&gt;
&lt;p&gt;For building &lt;a href=&quot;https://ridestats.app&quot;&gt;RideStats.app&lt;/a&gt; I make use of the &lt;code&gt;Map&lt;/code&gt; type in SwiftUI and it&#39;s amazing. It is rediculously limited though and is lacking 90% of the functionality that exists in the MapKit views.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Polyline paths&lt;/li&gt;
&lt;li&gt;Overlays&lt;/li&gt;
&lt;li&gt;Every feature that MapKit has but in a SwiftUI View&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Mixed Reality headset&lt;/h2&gt;
&lt;p&gt;Everything makes sense for this to happen this year. I&#39;m keeping my expectations open for just what it looks like but my guess is it will involve widgets and live activities somehow.&lt;/p&gt;
</content>
    <summary>Amy&#39;s list of things that would be nice to see at WWDC</summary>
  </entry>
  
  <entry>
    <title type="html">Showing heart rate in live activities</title>
    <link href="https://cuteios.dev/2023/04/08/heart-rate/" rel="alternate" type="text/html" title="Showing heart rate in live activities"/>
    <published>2023-04-08T00:00:00Z</published>
    <updated>2023-04-08T00:00:00Z</updated>
    <id>https://cuteios.dev/2023/04/08/heart-rate/</id>
    <content type="html" xml:base="https://cuteios.dev/2023/04/08/heart-rate/">&lt;p&gt;Let&#39;s have some fun and get to understand two concepts. The first is bluetooth devices and the second is live activities. We&#39;ll be walking through some of the interesting parts of a demo app which is available on &lt;a href=&quot;https://github.com/cuteiosdev/heart_rate_live&quot;&gt;GitHub&lt;/a&gt; and seeing just what makes bluetooth devices behave and send data.&lt;/p&gt;
&lt;h2&gt;What is Bluetooth?&lt;/h2&gt;
&lt;p&gt;Bluetooth is a wireless communication method defined by the &lt;a href=&quot;https://www.bluetooth.com&quot;&gt;Bluetooth SIG&lt;/a&gt; and is a great way for talking to peripherals that are mounted on a bike such as power meters and cadence sensors. We&#39;ll be talking to a heart rate monitor in this example.&lt;/p&gt;
&lt;p&gt;On apple platforms, the framework used is &lt;a href=&quot;https://developer.apple.com/documentation/corebluetooth&quot;&gt;CoreBluetooth&lt;/a&gt;. As well as providing abstractions around &lt;a href=&quot;https://developer.apple.com/documentation/corebluetooth/cbperipheral&quot;&gt;Peripherals&lt;/a&gt;, &lt;a href=&quot;https://developer.apple.com/documentation/corebluetooth/cbservice&quot;&gt;Services&lt;/a&gt;, and &lt;a href=&quot;https://developer.apple.com/documentation/corebluetooth/cbcharacteristic&quot;&gt;Characteristics&lt;/a&gt; it uses a &lt;a href=&quot;https://developer.apple.com/documentation/corebluetooth/cbcentralmanager&quot;&gt;Central Manager&lt;/a&gt; for discovering all of the peripherals that are around.&lt;/p&gt;
&lt;p&gt;To start making use of bluetooth peripherals, you need to have an instance of &lt;a href=&quot;https://developer.apple.com/documentation/corebluetooth/cbcentralmanager&quot;&gt;CBCentralManager&lt;/a&gt; and a class (yeah, needs to be an NSObject subclass) that conforms to the &lt;a href=&quot;https://developer.apple.com/documentation/corebluetooth/cbcentralmanagerdelegate&quot;&gt;CBCentralManagerDelegate&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Discovering bluetooth devices&lt;/h2&gt;
&lt;p&gt;Before we start looking for peripherals, we want to make sure that the required hardware is available for use. Your app will be told about the state of the hardware via the delegate method &lt;a href=&quot;https://developer.apple.com/documentation/corebluetooth/cbcentralmanagerdelegate/1518888-centralmanagerdidupdatestate&quot;&gt;centralManagerDidUpdateState(_:)&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;  public func centralManagerDidUpdateState(_ central: CBCentralManager) {
    switch central.state {
    case .poweredOn:
      startScanningForPeripherals()
    default: break
    }
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the manager is asked to discover services we need to tell it what services it should be looking for. If we pass &lt;code&gt;nil&lt;/code&gt; to &lt;a href=&quot;https://developer.apple.com/documentation/corebluetooth/cbcentralmanager/1518986-scanforperipherals&quot;&gt;scanForPeripherals(withServices: options:)&lt;/a&gt; we will see all peripherals. To limit these to just devices that support heart rate measurements, we use the service UUID of &lt;code&gt;180D&lt;/code&gt; that is defined by the &lt;a href=&quot;https://www.bluetooth.com/specifications/specs/heart-rate-service-1-0/&quot;&gt;heart rate service&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;  public func startScanningForPeripherals() {
    guard manager.state == .poweredOn else {
      return
    }

    manager.scanForPeripherals(withServices: [CBUUID(string: &amp;quot;180D&amp;quot;)])
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that we have asked the manager to scan for peripherals, we need to listen for what is found. As this happens at the discretion of the manager, we make use of the delegate function &lt;a href=&quot;https://developer.apple.com/documentation/corebluetooth/cbcentralmanagerdelegate/1518937-centralmanager&quot;&gt;centralManager(_:didDiscover:advertisementData:rssi:)&lt;/a&gt; to perform actions on the peripherals that we find.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;  public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
    guard peripherals.contains(where: { $0.id == peripheral.identifier }) == false else {
      return
    }

    peripherals.append(peripheral)
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As the peripherals are discovered, we want to be able to connect to them so we can start receiving values from them. To do this, we ask the manager to &lt;a href=&quot;https://developer.apple.com/documentation/corebluetooth/cbcentralmanager/1518766-connect&quot;&gt;connect&lt;/a&gt; to a device. We then get the details of the connected peripheral in the delegate function &lt;a href=&quot;https://developer.apple.com/documentation/corebluetooth/cbcentralmanagerdelegate/1518969-centralmanager&quot;&gt;centralManager(_:didConnect:)&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;  public func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
    details = peripheral
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the peripheral is connected, we then want to discover the services that are available on it. Doing this is requires that we first set the &lt;a href=&quot;https://developer.apple.com/documentation/corebluetooth/cbperipheral/1518730-delegate&quot;&gt;delegate&lt;/a&gt; property on the peripheral to a type that conforms to &lt;a href=&quot;https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate&quot;&gt;CBPeripheralDelegate&lt;/a&gt; which again needs to be a NSObject subclass. Once we have set the delegate we then need to call &lt;a href=&quot;https://developer.apple.com/documentation/corebluetooth/cbperipheral/1518706-discoverservices&quot;&gt;discoverServices(_:)&lt;/a&gt; on the peripheral using the &lt;code&gt;180D&lt;/code&gt; UUID for heart rate monitors.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;    peripheral.discoverServices([CBUUID(string: &amp;quot;180D&amp;quot;)])
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The delegate method &lt;a href=&quot;https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate/1518744-peripheral&quot;&gt;peripheral(_:didDiscoverServices:)&lt;/a&gt; will then be called with the peripheral having its &lt;a href=&quot;https://developer.apple.com/documentation/corebluetooth/cbperipheral/1518978-services&quot;&gt;services&lt;/a&gt; property populated. We can then ask the peripheral to discover the characteristics for each of the services. When scanning for characteristics, we use the &lt;a href=&quot;&quot;&gt;&lt;/a&gt; function on the peripheral instance passing it an instance of &lt;a href=&quot;https://developer.apple.com/documentation/corebluetooth/cbservice&quot;&gt;CBService&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;  func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
    peripheral.services?.forEach { service in
      peripheral.discoverCharacteristics(nil, for: service)
    }
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We now have the required data and connection to start receiving values for our peripherals.&lt;/p&gt;
&lt;h2&gt;Receiving data&lt;/h2&gt;
&lt;p&gt;As you can guess, our app is told about the discovered characteristics in the delegate method &lt;a href=&quot;https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate/1518821-peripheral&quot;&gt;peripheral(_:didDiscoverCharacteristicsFor:error:)&lt;/a&gt;. There are two types of values which are available. We can either get a value if it is supported and this is great for static values on a device. We can also listen for notifications of when a value changes. This is what we want for heart rate monitors and other characteristics whose values change over time. To listen for a value update notification, we call the &lt;a href=&quot;https://developer.apple.com/documentation/corebluetooth/cbperipheral/1518949-setnotifyvalue&quot;&gt;setNotifyValue(_:for:)&lt;/a&gt; function on the peripheral.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;  func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
    guard service.uuid.uuidString == &amp;quot;180D&amp;quot; else {
      return
    }

    guard let measurementCharacteristic = service.characteristics?.first(where: { $0.uuid.uuidString == &amp;quot;2A37&amp;quot; }) else {
      return
    }

    peripheral.setNotifyValue(true, for: measurementCharacteristic)
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The UUID for the characteristic representing heart rate measurements is &lt;code&gt;2A37&lt;/code&gt; and is defined as part of the &lt;a href=&quot;https://www.bluetooth.com/specifications/specs/heart-rate-service-1-0/&quot;&gt;heart rate service&lt;/a&gt; specification. The format of the bytes we get in the &lt;a href=&quot;https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate/1518708-peripheral&quot;&gt;peripheral(_:didUpdateValueFor:error:)&lt;/a&gt; delegate function are defined in the same specification. Being familiar with this dance is important so that we can parse the values.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;  func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
    guard characteristic.uuid.uuidString == &amp;quot;2A37&amp;quot; else {
      return
    }

    guard let data = characteristic.value else {
      return
    }

    heartRate = formatter.valueForData(data)
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The formatter is a helper type defined to extract the appropriate values from the raw Data instance that we get in the delegate function. This is defined as the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;  public func valueForData(_ data: Data) -&amp;gt; Int? {
    let byteArray = [UInt8](data)
    let firstBitValue = byteArray[0] &amp;amp; 0x01

    if firstBitValue == 0 {
      return Int(byteArray[1])
    }

    return (Int(byteArray[1]) &amp;lt;&amp;lt; 8) + Int(byteArray[2])
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Live Activities&lt;/h2&gt;
&lt;p&gt;A lot of fun comes when we background the app and can show the current heart rate as either a live activity or using the dynamic island on supported devices.&lt;/p&gt;
&lt;h3&gt;Handling background updates&lt;/h3&gt;
&lt;p&gt;To allow bluetooth to function in the background, we need to add some values to the &lt;code&gt;info.plist&lt;/code&gt; file. These values are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/documentation/bundleresources/information_property_list/nsbluetoothalwaysusagedescription&quot;&gt;NSBluetoothAlwaysUsageDescription&lt;/a&gt; for a nice description of why we need to use bluetooth&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/documentation/xcode/configuring-background-execution-modes&quot;&gt;Required Background Modes&lt;/a&gt; must contain &lt;code&gt;App Communicates using Core Bluetooth&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.apple.com/documentation/bundleresources/information_property_list/nssupportsliveactivitiesfrequentupdates&quot;&gt;Supports Live Activities Frequent Updates&lt;/a&gt; set to true so we can send frequent updates&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&#39;ve used background fetches before, you would think that we need to handle background tasks. This isn&#39;t the case with CoreBluetooth and your &lt;code&gt;CBCentralManagerDelegate&lt;/code&gt; conforming type will get called. When those delegate methods get called, it is possible to update the live activity.&lt;/p&gt;
&lt;h3&gt;Sending data to the live activity&lt;/h3&gt;
&lt;p&gt;Both Live Activities and the Dynamic Island exist as widgets and make use of configurations to update the data that gets shown. These configurations are value types that conform to the &lt;code&gt;ActivityAttributes&lt;/code&gt; protocol like the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;public struct WidgetsAttributes: ActivityAttributes {
  public typealias Content = ContentState

  public struct ContentState: Codable, Hashable {
    // Dynamic stateful properties about your activity go here!
    public var heartRate: Int

    public init(heartRate: Int) {
      self.heartRate = heartRate
    }
  }

  public init() {}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are two parts to the attributes being the data which doesn&#39;t change regularly and then the frequently updated content. For showing the heart rate values we want to be setting the current value in the content. We do this when we receive a value in the &lt;code&gt;CBPeripheralDelegate.peripheral(_:didUpdateValueFor:error:)&lt;/code&gt; function. We also want to check that live activities are supported which we do using the &lt;a href=&quot;https://developer.apple.com/documentation/activitykit/activityauthorizationinfo/areactivitiesenabled&quot;&gt;areActivitiesEnabled&lt;/a&gt; property on &lt;a href=&quot;https://developer.apple.com/documentation/activitykit/activityauthorizationinfo/&quot;&gt;ActivityAuthorizationInfo&lt;/a&gt; class. When updating the data for a live activity, we create a new content and then ask the activity to update using the content.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;    if ActivityAuthorizationInfo().areActivitiesEnabled {
      let content = ActivityContent(state: WidgetsAttributes.ContentState(heartRate: heartRate ?? 0), staleDate: nil)

      if activity == nil {
        do
        {
          let attributes = WidgetsAttributes()
          activity = try Activity.request(attributes: attributes, content: content)
        } catch {

        }
      } else {
        Task {
          await activity?.update(content)
        }
      }
    }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we are finished displaying the heart rate, we want to end the activity so that it&#39;s not being displayed any longer.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-swift&quot;&gt;    Task {
      await activity?.end(dismissalPolicy: .immediate)
    }
&lt;/code&gt;&lt;/pre&gt;
</content>
    <summary>A quick and fun tutorial for how to show data from a bluetooth heart rate monitor in a live activity</summary>
  </entry>
  
  <entry>
    <title type="html">Hello World</title>
    <link href="https://cuteios.dev/2023/03/13/hello-world/" rel="alternate" type="text/html" title="Hello World"/>
    <published>2023-03-13T00:00:00Z</published>
    <updated>2023-03-13T00:00:00Z</updated>
    <id>https://cuteios.dev/2023/03/13/hello-world/</id>
    <content type="html" xml:base="https://cuteios.dev/2023/03/13/hello-world/">&lt;p&gt;Welcome to my part of the Internet. My name is Amy and I&#39;m a macOS and iOS developer.&lt;/p&gt;
</content>
    <summary>Hello World, I am Amy</summary>
  </entry>
  
</feed>
