WWDC23 SwiftData Lab Notes

I attended a WWDC23 SwiftData lab and asked questions in the data-frameworks Slack QA session. This is my summary of what I learned.

Note: This is not a verbatim transcript of conversations. I’ve summarised from my notes and memory so it’s always possible I misunderstood something. Apple engineers also stated that SwiftData will continue to develop during the beta period.

Asynchronous Operations

When loading the container does it happen asynchronously? Do I need to configure the container to load asynchronously as with Core Data to avoid blocking the UI?

There should be no blockage on the mainUI thread, please file a feedback report with a sample project if this a scenario you have experienced.

How do you perform bulk operations on a background thread?

You can create a ModelContainer on a separate actor to perform background work like a bulk insert or deletion. The Model and ModelContext are not sendable, you cannot share them across actors.

You can pass an object’s persistentIdentifier between contexts and then ask a context to fetch the object with that identifier (like Core data).

CloudKit sync

If I have a CloudKit container entitlement in my app, can I disable the SwiftData container from using it for previews and unit testing? For example, in Core Data I can delete the CloudKit options in the persistent store description before loading.

Disable it in the model configuration. There are some known issues in seed 1 of SwiftData. Please file a feedback report for this issue and we will take a look!

Feedback filed: FB12292537

When syncing Core Data with CloudKit you cannot have unique constraints and all relationships are optional. Do those same contraints apply when using SwiftData?

Yes. File a feedback report if you would like to see changes.

When syncing with CloudKit how do I dedupe data? Can I still register for NSPersistentStoreRemoteChange notifications and fetch the history as with Core Data?

Indeed you can by setting up a parallel stack with Core Data that allows you to consume Persistent History and do that processing.

Can SwiftData sync with public and shared CloudKit databases?

SwiftData only supports the private CloudKit database. Use co-existence with a Core Data NSPersistentCloudKitContainer to perform the mirroring with shared or public databases.

Is there any sample code showing CloudKit sync with SwiftData?

Not yet. Check the SwiftData documentation for updated sample code.

Predicates and Queries

Is there a way to update the sortOrder or predicate of a query at run time similar to how @FetchRequest works?

Not at this time, please file a Feedback report and we’ll look into it!

The suggested workaround is to pass the sort order and predicate as parameters to the view and create the query in the init.

Feedback filed: FB12292784

Do predicates support complex expressions? For example, in Core Data I often use NSExpression to fetch min and max values of a field.

I think the answer to this will depend on which expressions you’re looking to support, so feel free to clarify or ask in the thread about specific expressions. But predicates with SwiftData do not currently have explicit support for some of the mathematical/statistical values such as min/max - feel free to file a feedback about those if you’d like to see them added!

Feedback filed: FB12292503 requesting support for min/max expressions.

Can a query return data grouped into sections (like NSFetchedResultsController)?

Please file a feedback report for this enhancement!

Feedback filed: FB12292612

Observing Model Objects

In Core Data an object can fault and it’s properties become nil. Can that happen with SwiftData?

No. SwiftData supports internal Futures like CoreData, but at different granularities since value type properties can’t support side effects.

What happens when I have a view observing a model object that is deleted elsewhere? Is there a way to detect the object has been deleted?

See the isDeleted flag.

The trips sample code crashes with two windows open on an iPad (see FB12272702). One window showing a list of trips, other window showing a trip detail. Deleting the trip from the list window causes a crash when changing the now deleted trip in the detail view window.

As a workaround, can you try calling save() after the delete() to see if that resolves the crash?

But the real question is what should happen in this case? It would be nice to have some way to dismiss the detail view once the object has been deleted.

In the view that is observing the model, could check if the instance isDeleted()

Feedback filed: FB12272702 saving or checking for isDeleted do not yet workaround the crash.

Saving

When should I not rely on autosave?

Autosave is on by default. Saves happen on app lifecycle changes and from a timer on context changes. Manually save if you need something to update immediately.

Migrating From Core data

Any tips on migrating an app from Core Data to SwiftData?

Consider coexistence, running Core Data and SwiftData stacks talking to the same store. Pay attention to name spacing so that Core Data and SwiftData entity names do not collide. Keep the two schemas in sync.