Arnaud Joubay Profile picture
Jun 10 25 tweets 11 min read
I think Core Data and NSPersistentCloudKitContainer deserve more love.

I see it like parents: they do a 1000 things you don't imagine need to be done or… until you grow up.

Anyway, here are things I spotted in the lounges that are worth knowing about.

#WWDC22
Don't purge the history when using NSPersistentCloudKitContainer


wwdc22.slack.com/archives/C03GS…
Using NSPersistentCloudKitContainer and tempted to add a toggle sync button?
Don't do it.

There are many technical reasons not to do it, but also, the user already made the choice when enabling iCloud Storage. It should just work.

wwdc22.slack.com/archives/C03H0… Image
When importing data (for instance after a re-install), data download happens in random order.

If your app relies on time for its data (say, a tracker app 😏), you should be aware of that: data from 18 months ago could be downloaded after data from 3 months ago. Image
If the above is an issue, or if you want to use mechanisms that CloudKit doesn't support (eg unique constraints), the recommended approach is to have 2 stores (one for the cloud, one local) and to move data between both.

wwdc22.slack.com/archives/C03H0… Image
This comes up often. If you notice that "CloudKit and CoreData only seem to sync between devices when I quit and relaunch the app", there are 2 things to be aware of:
1. you need to enable remote notifications
2. IT DOESN'T WORK IN THE SIMULATOR ANYWAY

wwdc22.slack.com/archives/C03H0…
CloudKit apps crash on launch with Xcode 14 first beta and iOS 16 Simulator

wwdc22.slack.com/archives/C03H0…
NSPersistentStoreRemoteChangeNotification only informs you that the store file has changed, not that changes were imported from CloudKit.
NSPersistentCloudKitContainerEvent does

wwdc22.slack.com/archives/C03H0… Image
When deduplicating data with relationships, beware that the object at the other end might be nil.

I'm not entirely sure how to deal with this at this point, but it may explain an issue I have.

wwdc22.slack.com/archives/C03H0… Image
Not sure if you want CloudKit, iCloud Documents or NSUbiquitousKeyValueStore? Read this doc

developer.apple.com/documentation/…
AFAIK, while you can tell if a container is importing/downloading data from CloudKit (developer.apple.com/documentation/…), there is no way to know if your container downloaded all the data known by the Cloud.

wwdc22.slack.com/archives/C03H0…
The above is puzzling to me.

In distributed systems, there's no way to tell if "all devices are synced".

But, since CloudKit is the source of truth, I don't understand why we can't check whether we know as much as it does or not.
Currently, synchronizing only happens when your app runs in the foreground.

This should be improved in the future, but until then, use background tasks.
developer.apple.com/documentation/…

wwdc22.slack.com/archives/C03H0… Image
You don't *have* to create a new model version for lightweight migrations anymore 🤯

wwdc22.slack.com/archives/C03GS…
"Evolve your Core Data scheme" talks about Staged Lightweight Migration… but no code sample explains how to transform your data.

But, I did that for my 4.0 upgrade so, DM me and we can talk about it.

developer.apple.com/wwdc22/10120
wwdc22.slack.com/archives/C03GS… Image
By the way, if you implement a background task as suggested, remember that it doesn't work in the simulator either (you can trigger it manually though: developer.apple.com/documentation/…)

Never purge… unless it becomes problematic 😅.

But then you should:
* keep around 1 year of history as a minimum bar
* prune it after a successful NSPersistentCloudKitContainerEvent of type Export
wwdc22.slack.com/archives/C03GS…
Image
Remember when I said that CD/NSPCKC does more work than you'd think?
Here's an example.

wwdc22.slack.com/archives/C03GS… Image
To backup the SQLite db, use replacePersistentStore() with sqlite3_wal_checkpoint to get a single file.

For that you have 2 options (next 2 tweets)
developer.apple.com/documentation/…
wwdc22.slack.com/archives/C03GS…
Option 1: directly from a persistent store description

storeDescription.setValue("DELETE" as NSObject, forPragmaNamed: "journal_mode")

developer.apple.com/documentation/…
Option 2: as you set the store options

storeOptions[NSSQLitePragmasOption] = ["journal_mode": "DELETE"]
The batches of 200 is something I observed myself.
1-2s per operation means 83-167 minutes per million records.
wwdc22.slack.com/archives/C03GS… Image
But since CloudKit is using background tasks (not BGProcessingTask) and they have 30 seconds to end, that's only 15-30 operations or 3000-6000 records.

Unfortunately, it seems NSPCKC doesn't know how to properly handle the fact that it ran out of time.
That being said, that won't stop your app from downloading your data.

CloudKit will start to download data in a background task and be abruptly interrupted after 30 seconds, but it still imported data and it will launch another task to keep going.
This is where a BGProcessingTask should help I guess.

You'll still experience the interruptions of the successive CloudKit tasks, but the app won't have to be in the foreground for these tasks to run.

• • •

Missing some Tweet in this thread? You can try to force a refresh
 

Keep Current with Arnaud Joubay

Arnaud Joubay Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

PDF

Twitter may remove this content at anytime! Save it as PDF for later use!

Try unrolling a thread yourself!

how to unroll video
  1. Follow @ThreadReaderApp to mention us!

  2. From a Twitter thread mention us with a keyword "unroll"
@threadreaderapp unroll

Practice here first or read more on our help page!

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just two indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3/month or $30/year) and get exclusive features!

Become Premium

Don't want to be a Premium member but still want to support us?

Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal

Or Donate anonymously using crypto!

Ethereum

0xfe58350B80634f60Fa6Dc149a72b4DFbc17D341E copy

Bitcoin

3ATGMxNzCUFzxpMCHL5sWSt4DVtS8UqXpi copy

Thank you for your support!

Follow Us on Twitter!

:(