Core Data Quick Start in SwiftUI
Core Data Quick Start in SwiftUI
In SwiftUI
[Brief introductory description of what this chapter contains.]
Mark Moeykens
www.bigmountainstudio.com A CORE DATA REFERENCE GUIDE
1 FOR SWIFTUI DEVELOPERS BigCoreMountain
Data Quick StartStudio
in SwiftUI
Version: 22-JUNE-2022
©2021 Big Mountain Studio LLC - All Rights Reserved
Next, I would like thank Chris Ching who finally convinced me to learn And finally, I would like to thank the creators of all the other sources of
information, whether Swift or Core Data, that really helped me out and
Core Data and instructed me on this topic.
enabled me to write this book. That includes Apple and their documentation
and definition files, Donny Wals, Antoine van der Lee, Paul Hudson, and
I would also like to thank my friends who always gave me constant Mohammad Azam.
feedback, support, and business guidance: Chris Ching, Scott Smith,
Rod Liberal, Chase Blumenthal and Chris Durtschi.
I would also like to thank the Utah developer community for their
help in making this book possible. This includes Dave DeLong and
Andrew Madsen.
I created a code editor color theme for a high-contrast light mode. This is the theme I use for the code throughout this book.
If you like this color theme and would like to use it in your Xcode then you can find it on my GitHub as a gist here.
💡
If you download the theme from the gist, look at
the first line (comment) for where to put it so
Xcode can see it.
Embedded Videos
💡
In some ePUB readers, including Apple Books, you
might have to tap TWICE (2) to play the video.
There are similar patterns that can be found when you have applications working with data.
Core Data is no different.
First, you will learn some concepts. No code in this chapter.
Then you will learn what Apple calls each of these parts in the Core Data framework. In the end, you will be able to THINK with Core Data
concepts.
Core Data Concepts
The Flow
Let’s go over the 4 main components used to work with Core Data in SwiftUI. You will learn the real names and purposes behind these concepts.
We won’t get too technical. This chapter will give you a good overview of the pieces that make up Core Data and how to think with it.
1 2 3 4
1. Data Model
The first part of the flow is the data model. You will learn what a data model is (and what it is not).
2 3 4
Data Models
struct Person { This defines a You have probably created a
let name: String data model but struct or a class to hold data.
let age: Int there is no actual
} data in it. These classes and structs are
called data models.
struct DataModels: View {
@State private var name = "" Data models are populated with
@State private var age = 0 values and used in some way.
The model is the definition of how data will be structured The object is an instance of the model that is populated
or organized. It defines property names and types. It can be with data. For example, the newPerson variable here is
a struct or a class. an object:
struct Person {
let name: String let newPerson = Person(name: name, age: age)
let age: Int
}
💡
Core Data can’t use the Person struct as it is
defined here. You will have to define it a different
way. See next page.
This helps Core Data understand how you want your data
structured.
This book will walk you through how to use this and set it up. The data model
💡
Think of “Attribute” as “property”.
This file just holds the definition of objects, like property
names and their types (string, bool, etc). The purple icons just represent the
data types specified.
It doesn’t actually hold any values.
N = Number
This will actually replace the Person struct on the previous S = String
page.
2 3 4
Person
name: String
age: Int
When your app has data, you have to store it someplace where it can persist so when the app is closed or if the device loses power it won’t
disappear. This chapter talks about the subject of persistence.
Reads Model
3 4
Persistent Storage
When an app saves data it will store it somewhere so that data can then persist, even when the power is turned off or the app is closed.
Apps on your iPhone are stored so they can persist if your phone loses all power. All iPhones have a physical component that can store apps and data.
A storage
Storage with Power device a solid Storage with no Power
state drive
(SSD).
💡 Core Data will store values to the physical storage on the device so it can persist after closing the app or shutting off the device.
NSPersistentContainer
Core Data uses the NSPersistentContainer to store data so it persists on the device. This IS the toolbox. The NSPersistentContainer has quite a few
tools we can use.
The NSPersistentContainer:
• Reads your Data Model and sets it up
for use
• Controls where your data is persisted
on the device
Store data Data Data • Is responsible for loading up your
Data data from the persistent storage so
Data
your app can use it
💡
Note: NS stands for “Next Step” (NeXTSTEP) which was an
operating system that Apple bought in 1996 and became the
foundation of macOS in 2000. Yeah, it’s old. But it’s continually
being worked on.
Container
Think of a container as a box that can hold many things. A container can hold tools, food, pencils, etc.
In programming, containers can hold a collection of other objects.
The NSPersistentContainer is like a toolbox (container) that will provide you with almost every tool you might need to work with Core Data.
💡
Many of these tools were separate. Developers had to do a lot of setup work to make them all work
together in the past.
But Apple developers made Core Data way easier to use with the NSPersistentContainer.
Data Objects
Data Model
Describes what the data will Person
class Person {
look like.
name String var name = “Natasha”
var age = 34
age Int
}
class Person {
var name = “Mark”
var age = 51
}
Data Values
Actual values
name age
💡
Why isn’t this part in the flow?
Natasha 34 I intentionally left out the data values from the flow because you don’t
Mark 51 have to do anything to get it working.
Data
Reads Model
Data
3 4
Person Data
name: String Data
age: Int
Once Core Data understands the data models and where the data is stored, it can retrieve and give data objects to your app.
At the end of this section, you will understand more about how and where data objects are managed.
Save changes
Memory
When any application works with data or data objects, it is usually done in memory or RAM. “RAM” is short for “random access memory”.
Think of RAM or memory as temporary. If the device loses power, all the data that is in memory is gone.
The operating system gives your app memory to work within. When you close the app, the operating system reclaims it and any data within is gone.
Core Data will use memory to temporarily store data changes. This is useful in case the user changes their mind and decides not to
💡 save or delete data (undo).
It’s also useful because memory is super fast.
NSManagedObjectContext
Core Data uses the NSManagedObjectContext as a space to let you freely change data in memory. It is where updates, deletions, and the creation of
new data objects take place.
You manage objects here. (Remember, data objects are data models that have values.)
NSManagedObjectContext
(In Memory)
The NSManagedObjectContext:
• Enables you to fetch specific data
objects from persistent storage
• Manages object changes in memory
until written to the persistent store
• Allows you to undo changes
• Has the ability to perform data object
work in the background
Fetched Data
Changed Data
Deleted Data
New Data 💡
All of these data object changes are just in memory.
Managed Object…”Context”
The word context means “everything related to some event, or idea so you can make sense with what is being said or shown”.
When you have data objects in memory, the operating system has to know what this memory is related to. Is it for App A or App B?
So context lets people and computers know how the things in memory are connected with which app and what they are used for. One app can have
many contexts being used for different purposes.
iPhone Memory
Data Context If your app is going Drawing Context If your app works with
to work with data drawing graphics, it will
objects, it will need need some space in
some space in memory memory to work with that
to work with that data. drawing data.
Note: There are many contexts for many frameworks and technologies within the available libraries used for developing apps.
💡 Here, you see examples of data and drawing contexts. When you see “context”, think “space in memory to work within”.
I will give you a place in memory (context) where you can make all of your data
object changes.
Let me know when you are done and I will save all your changes to the store.
NSPersistentContainer NSManagedObjectContext
Data Data
Reads model Data Provide data Data
Data Data
4
Person
name: String
Changed Data Changed Data
age: Int Deleted Data
Deleted Data Save changes
New Data New Data
2 1
Fetch data I need data
Mark 51
Data is loaded when
requested from the view.
Jaque 42
3 4
“Mark”, 51 “Mark”, 51
Load data Display data Chase 34
“Jaque”, 41 “Jaque”, 41
“Chase”, 34 “Chase”, 34
Paola 28
“Mark”, 51 6 “Mark”, 51 5
“Jaque”, 42 “Jaque”, 42
Persist data Save data Save
“Paola”, 28 “Paola”, 28
4. The View
When your app starts there is a particular order in which it initializes Core Data for use.
You will learn this order and the idea of how views work with Core Data in this section.
The App
2 3
The NSPersistentContainer is created. The Data Model + Data Values are read.
4 5
“Mark, 51
“Paola”, 18
Using @Environment
A common practice in SwiftUI apps is to store the
Environment NSManagedObjectContext in the environment.
This way it is available to all views so you can fetch and save
data. The View
Data Data
Data Data Saving your changes is also super easy.
Summary
You’ve learned a lot of concepts around Core Data. You’ll be using these concepts all throughout the book. So let’s summarize them.
Stores Data
Provides a place to
Reads Model change data
The Flow
Each of the 4 parts all have their own responsibilities.
In the previous pages, you learned about the 3 main tools the app needs to work with Core Data. You should have a pretty good concept of
what they are and how the app uses them.
Now you’re going to learn what those concepts look like in code as we set up a data model, add some data and show it in a SwiftUI view.
First Example
By the end of this section, you will learn the basics of creating and setting up a data model in Xcode.
xc - Xcode
- FirstExample.xcdatamodeld
- FirstExample.xcdatamodel (no “d”)
- contents
4
1. Click the Add Entity button
2. Give your entity a name
3. Click the + button in the Attributes 3
section
4. Add a name and assign a type
1
💡
The editor will force you to make the
first letter in entity names uppercase.
?
It will also force you to make attribute
names start with a lowercase letter. Can I change the position of attribute names?
Think of entities as classes and No, they are sorted alphabetically. Sometimes you will notice they are in random order when you first
attributes as properties. add them. But if you close this file and open it again, the attributes are sorted alphabetically again.
Attribute Types
You probably noticed that the available Attribute Type Swift Type General Information
attribute types didn’t have a plain Int as Binary Data Data When you want to store images, videos, sound files, or any other
we used in our struct. data objects
Boolean Bool True or false
Numbers can be broken down into how
Date Date Dates and times
big the number can get or the range of
values they offer. Decimal Decimal Highest level of precision. Great for currencies.
Double Double More precise than a Float (at least 15 decimal places)
This table will help you decide which
types to use. Float Float A number with a decimal when you don’t need the greatest precision
Stores Data
Provides a place to
Reads Model change data
A common practice is to create your persistent container when your app starts or when you first need the data.
And you probably want to keep it alive for the life of your app (or the life of the views that need it) so you don’t have to keep creating it.
import CoreData
When the persistent container is created, it needs the name of the data
class FirstExampleContainer { model to read.
The name should be exactly the same name as the file name.
let persistentContainer: NSPersistentContainer
init() {
persistentContainer.loadPersistentStores { _, _ in }
}
Xcode Project Navigator
}
Now that the persistent container knows what the data should look like, we can load
the persistent stores where the data exists.
The closure and the parameter names are intentionally left blank. This is where you
check for and handle any errors. We will cover this later in the book.
2 Steps Done
We have our data model defined and we created our persistent container. The next step is to set up the managed object context in a way that our views
can use it.
Stores Data
Provides a place to
Reads Model
change data
3. The Managed
Object Context
We need to set up a space in memory (context) to manage our data objects. SwiftUI has a really easy way in which we can do this.
import SwiftUI
The environment modifier provides a special
Remember, persistentContainer is the property
property just for your managed object
@main we created to hold our NSPersistentContainer.
context.
struct SwiftUI_CoreDataApp: App {
var body: some Scene {
WindowGroup { Persistent
FirstExampleView() containers give us
.environment(\.managedObjectContext, FirstExampleContainer().persistentContainer.viewContext) a managed object
}
context
(playground in
}
memory) to make
}
changes to data.
💡 💡
Note: The way environment modifiers work is they make an object
available to the view it is attached to AND all child views from there. More Info: If you want to learn more about how the environment
This provides views with a way to fetch data, make changes, and works, take a look at the Environment chapter in the “Working with
save data. Data in SwiftUI” book.
3 Steps Done
The persistent container is created and the viewContext (managed object context) is added to the environment. Now the view has to access the
managed object context so it can get some data and display it on the screen.
Stores Data
Provides a place to
Reads Model
change data
4. The View
With Core Data set up, it is now time to start working with data objects.
@FetchRequest Concept
The view is going to use a property wrapper called @FetchRequest to retrieve data from the managed object context. The request is passed from the
view to the managed object context.
@FetchRequest
“I need data.”
@FetchRequest
“I need data.”
@FetchRequest
Here’s your first view using Core Data. It’s not very exciting. We will add data on the next page.
No ID?
How come there is no id specified for the List view?
The person’s name is an optional string. You don’t have to do this if your items
Core Data defaults many of the types to conform to Identifiable though.
optionals.
The good news is Core Data
One way to handle this is with a nil coalescing automatically makes your entities
operator (??). conform to Identifiable for you so
you will never have to specify the id.
The @FetchRequest didn’t have to somehow What happens to the data after I quit the
connect to the managed object context that app?
we added to the environment? When the new data objects were created we
The @FetchRequest is so smart that it called the managed object context’s save()
automatically looks for the managed object function. This persisted the object to the store.
context in the environment. So if you quit the app the data is preserved.
If you re-open the app, the data is loaded from
If it doesn’t find one, you will see a purple the persisted store again and displayed on the
memory warning in Xcode that says: screen.
“Context in environment is not connected to a
persistent store coordinator”
How do I delete this data?
Use width: 214 This is when you know you forgot to set the
This book will show you how to do that but for
managed object context.
now, you can delete your app from the simulator.
That will remove the data from the persisted
storage that was connected to the app.
4 Steps Done!
You have now successfully added data to your persistent store and have data successfully being fetched and shown on the view.
Stores Data
Provides a place to
Reads Model
change data
Create Data
Summary
When looking at the total amount of code we had to create to get Core Data working, there really wasn’t all that much between the 3 files.
1
class FirstExampleContainer {
let persistentContainer: NSPersistentContainer
First, we created a class to
init() {
persistentContainer = NSPersistentContainer(name: "FirstExample") create our persistent
persistentContainer.loadPersistentStores { _, _ in } container.
}
}
2
@main
struct SwiftUI_CoreDataApp: App { And then we added the
var body: some Scene { managed object context
WindowGroup {
FirstExampleView() (viewContext property) to
.environment(\.managedObjectContext, FirstExampleContainer().persistentContainer.viewContext) the environment’s
}
managedObjectContext.
}
}
Summary
3
struct FirstExampleView: View {
@FetchRequest(sortDescriptors: []) private var people: FetchedResults<PersonEntity>
@Environment(\.managedObjectContext) var moc
The Core Data Concepts and First Example chapters were meant to help you understand the main parts of Core Data and to see how easy it
can be to get started. This is your foundation to build on.
Many times you want to see a preview of the UI you are building WITH mock data. But how can you add mock data to Core Data without it
persisting? What if you want to test deleting data? You don’t want to keep having to add the same data over and over again.
In this chapter, I’ll show you how to set up mock data so you can see it in your SwiftUI Preview.
Mock Data
Data Model
For this chapter, we are going to use a simple data model with one entity and two fields. It is in a file called FriendsDataModel.xcdatamodeld.
FriendsDataModel
💡
As a convention from this
point on I will be adding
“DataModel” to all of my data
model file names.
class FriendsContainer {
let persistentContainer: NSPersistentContainer
init() {
persistentContainer = NSPersistentContainer(name: “FriendsDataModel")
As you can see the persistent store is a
sqlite file with the exact same name as
print(persistentContainer.persistentStoreDescriptions.first!.url!.absoluteString) the name of our data model
“FriendsDataModel”.
Optional("file:///Users/mark/Library/Developer/CoreSimulator/Devices/FDCCB8F9-79E4-499C-8CFD-2E8243B84B08/data/
Containers/Data/Application/490E0318-F97F-4BD5-907B-708B2C0D0ADE/Library/Application%20Support/
FriendsDataModel.sqlite")
You want to be able to toggle this temporary path for mock data because your real app will not use this path.
persistentContainer.loadPersistentStores { _, _ in }
}
}
Mock Data
class FriendsContainer {
let persistentContainer: NSPersistentContainer
if forPreview {
persistentContainer.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
}
persistentContainer.loadPersistentStores { _, _ in }
extension FriendsContainer {
func addMockData(moc: NSManagedObjectContext) {
let friend1 = FriendEntity(context: moc)
friend1.firstName = "Chris"
The newly created managed
friend1.lastName = "Bloom" object context is passed in
because you need this whenever
let friend2 = FriendEntity(context: moc)
friend2.firstName = "Jaqueline" you create a new entity, such as
friend2.lastName = "Cruz" the FriendEntity.
let friend3 = FriendEntity(context: moc) OK, you have a temporary
friend3.firstName = "Rodrigo" Newly created entities are first location to play in and some
friend3.lastName = "Jones" added to context (memory) and mock data loaded up.
// ... then are saved and persisted on
the disk. Now let’s set up the SwiftUI
try? moc.save()
} preview!
}
PreviewingData_Intro()
.environment(\.managedObjectContext,
FriendsContainer(forPreview: true).persistentContainer.viewContext)
List(friends) { friend in
Text(friend.firstName ?? "")
.font(.title)
PreviewingData_Intro()
.environment(\.managedObjectContext, FriendsContainer.preview)
In your data model, most of your entity attributes will be optional types. You don’t have a choice in this matter.
This means when you want to display data, there’s a lot of optional handling because if a value is nil, you have to provide a default value.
Data Model
For this chapter we are going to use this data model. It is in a file called BooksDataModel.xcdatamodeld.
BooksDataModel
Handling Nils
struct DisplayData_Intro: View {
@FetchRequest(sortDescriptors: []) private var books: FetchedResults<BookEntity>
File Organization I keep my data model, container, and entity extensions all in the same folder.
If you are using the companion Xcode project, you will find all the data
models and related files in the Data Models folder and within their own
folders from there.
Remember:
• Data Model - Tells Core Data what the data will look like.
• Container - Creates your persistent container and gives you a managed
object context.
• Entity Extensions - Extends the autogenerated entity classes with your
own properties to format the values and handle nils for use on your UI.
Thank you for reading the Core Data Quick Start in SwiftUI book. • How do you use concurrency in Core Data?
• What can I do to allow users to undo and redo Core Data
This is just the BEGINNING of a larger book called Core Data changes?
Mastery in SwiftUI. In the Mastery book you will learn much more • Can I split out my data model into multiple entities and connect
about Core Data and be able to answer questions such as: them with relationships?
• How do I create fetch requests that can filter and sort my data? • How do I use Core Data with observable objects and SwiftUI
• Can I fetch data that can be bound to a List with sections? views?
• Is there a way to add data validation to my data model and show • Can I version my data model with changes for new versions of my
the results in my SwiftUI views? app?
• How do I use the managed object context to insert, update, • How can I use Core Data and sync with iCloud between devices?
delete or check for changes before saving?
THE END
76