Converting CoreData applications with lots of existing data to SwiftData
SwiftUI/CoreData/SwiftData
Apple has introduced the SwiftData framework to replace CoreData as a persistence mechanism in 2023’s Worldwide Developers’ Conference (WWDC). There were a few refinements to SwiftData since then, but bigger changes may be in the horizon for the 2024 WWDC, although I suspect the focus for this c
onference will be Apple’s AI initiatives (I sincerely hope).
Apple has facilitated developers’ move from Core Data to SwiftData by providing some insights and they also note that “mixed mode” persistence, namely using Code Data and SwiftData side by side is possible.
I will look at some options in this conversion by converting a simple application.
This sample application has a single record of interest that is called Author, given that it is an authors’ database that the application is managing.
I created a Core Data project with the name Authors. Here is a snapshot of what the data design looks like.
As you can see, this simple table has an entity named Author, with properties named name, surname, birthyear, gender and a notes field. I set the entity with the option category/extension to be able to extend the Author class as required in code.
You can find the ContentView source partly below. It is a simple NavigationView with a list of authors displayed. When the user clicks on an author, then an EditAuthor view opens and enables the user to edit the data.
Running this and populating the data, we get a list of authors which are then stored in a CoreData database.
Let us now assume that we have a lot of authors in this database, say 5000. We want to transform our application to use SwiftData instead of CoreData. How can we do this without losing the data in our database?
We select the XCode model and go to Editor/Create SwiftData Code. We then see the list of all Core Data entities for which SwiftData code will be generated.
XCode then creates the Swift file(s) for the entities. In this case it created yet another Author.swift file which is the equivalent class for SwiftData.
Since this is the only thing XCode does for us to help this conversion, we still have a lot of work to do. We have to somehow populate the SwiftData database (which still has CoreData underneath with details hidden from us by the SwiftData layer) with the existing data.
Since we can not use the same name for a CoreData and a SwiftData class, we have to rename one. The easiest is to rename the new SwiftData class, so I rename it to AuthorRecord and provide a proper initialiser. While doing this, I also removed the optionals since SwiftData does not require them to be optional.
Now we add the initialization of the SwiftData model in the main application. Since we have only one class we only add AuthorRecord.
Now we can add a converter. I’ll do it by adding a button specific for this in the main view (ContentView). This button will trigger the conversion method (convert).
We import the context for SwiftData to the main view.
Here is what convert does. This view already loads all Author objects in CoreData. We then create a AuthorRecord object for each object stored in CoreData, copy all the properties from the old object to the new and save the new object to the new SwiftData database. In principle we do not need to explicitly save when we set the SwiftData database to have auto-saving. However, during my early work with SwiftData, I noticed that autosaving does not always work, so it is safer to actually do an explicit save.
Now we have the same data saved in the SwiftData database as well. However, our interface still uses the CoreData based data store. Thus we have to replace that part of the code to read from the SwiftData database. (By the way, if you do not specify any parameters when initiating the database, XCode uses an sqlite database stored as default.db).
We replace the FetchRecord structure in the main view with a Query macro used by SwiftData. It is much easier to work with objects with SwiftData, since we have simple arrays storing the objects retrieved from the database instead of complex structures like FetchedResults<AuthorRecord>.
With a few minor tweaks, we complete the code conversion, remembering to delete the full CoreData model from the XCode project. When we run the application, we have kept all of our data and work with SwiftData now.
,