-
Everything is hard!
-
I need to commit.
-
I need to find my git rhythm.
-
Just realized my last commit was 30 days ago. That’s a long time. Too long.
-
It feels good to speak words.
-
Making a good app is hard.
-
XML 🤮
-
I still get genuinely surprised and excited how fast computers can do things.
-
Three steps forward.
-
One step forward, six steps back.
-
Rethinking how my entire codebase is structured.
-
Pausing to breathe and rethink my model.
-
Chasing my tail trying to defeat some SwiftData Predicate bugs.
-
For the time being, I’m moving the writer app from macOS to iPadOS. Because I can use Swift Data with no friction in the Xcode iPad simulator. Once I update my development Mac to Sonoma, I can start building for Mac again but this will hold me over for now.
-
I want to use Swift Data, but it’s only supported in macOS 14 Sonoma. And my development machine is running macOS 13 Ventura, so it won’t build or run with a minimum deployment of 14.
-
The macOS app is a helper tool for me to process data and manage its representation in CloudKit. But it’s currently stateless. It decodes JSON and writes directly to a public database – so I can reset the CloudKit developer environment as needed and quickly stand it back up with schemas and records.
But as I started modeling a new metadata type that isn’t represented in the source JSON, I realized the Mac app needs a data store of it’s own.
CloudKit
Friday July 28, 2023 -
Commenting out a framework. Learning from what breaks.
-
Maintaining the source schemas from each data source as its own record type has been a good choice. Now I have a small catalog of data from 3 places loaded into CloudKit. And a simple iOS app with a picker between 3 SwiftUI views – each tuned to its source. So each feels the same.
Next I’ll model some common metadata concepts from across the 3 schemas as new CloudKit record types. I’ll expand the macOS writer app to run queries against the existing data catalog, create new CloudKit metadata records and build an object graph between content and tags using
CKRecord.Reference
. So the iOS reader can query against these common metadata records, and get back references to records from all 3 sources.CloudKit
Wednesday July 26, 2023 -
Sharing bits of daily progress has been energizing for me.
I’d fallen into the the trap of I’ll share something when it’s done – but nothing is ever done.
-
I went down the path of trying to define a source agnostic schema, thinking I would transform all the incoming data to a common record type in the macOS app before loading it into CloudKit.
But this adds some pressure to get the data normalization “right” on ingest. Now I’m exploring an alternative approach, where I maintain a 1:1 relationship between data source schemas and CloudKit record types.
CloudKit
Monday July 24, 2023 -
I’ve posted more on micro.blog in the last 5 days than I have on all social media in the last 2 years.
-
micro.blog(ing) has been very good for me
-
I updated the macOS writer app to publish 25 actual records to CloudKit – and in turn, the iOS reader to fetch this new data. Each record includes a
title
and a remoteimageURL
. The titles appear right away, but theAsyncImage(url:)
SwiftUI View has some noticeable latency when loading images. Tomorrow I’ll try saving them directly to CloudKit as aCKAsset
when I create the records and see if this improves performance.Progress is tangible though. This morning the app only displayed temp strings. Tonight it’s showing actual content and it’s starting to feel like a real app.
T minus 57-days…
CloudKit
Sunday July 23, 2023 -
Yesterday I realized my database had duplicate records, and that CloudKit doesn’t support unique constraints. So I added a check to make sure a record doesn’t exist before writing it in. My code evolved into a mix of bits from the documentation and a few phone-a-friends with ChatGPT. It worked. But how?
Today I learned thefetch
method onCKDatabase
takes in a completion handler as a parameter, which gets called after the operation with the outcome of the fetch. The completion handler itself takes in a singleResult
parameter, which is a basic type from the Swift Standard Library.@frozen public enum Result<Success, Failure> where Failure : Error { case success(Success) case failure(Failure) }
Notice the
<Success, Failure>
in the enum’s declaration. It’s using Swift Generics as a placeholder to represent any Success or Failure value. In CloudKit, these are defined by thefetch
method to return either a tuple of results, or an error if the request fails. So in the case of.success
, I get back an array ofmatchResults
. If this array.isEmpty
, a write won’t create a duplicate record.CloudKit
Sunday July 23, 2023 -
Taking some time to understand all of yesterday’s code before forging ahead.