After having tackled concurrency and networking this time we had an opportunity of concentrating on saving data. We learn about how to save app data in the local storage of the devices using Files, Property Lists and Core Data.
Saving data in iOS
- Each app is given its own sandbox, a place where we can store and manipulate files exclusively within each app.
- In Swift, directories are represented using the URL struct and we can use the file manager to manipulate the directory.
- We can use the default
FileManager.default.urls(for: in:). For first parameter we specify that we want a document directory with
.documentDirectory, the second argument is used to tell the file manager that the directory belongs to the user with
.userDomainMask. The method returns an array of urls, and since there is only one document directory per iOS app we refer to it with
Core Data is an extremely powerful framework that abstracts much of the details of how and where the data is actually stored. This allows you to focus on what you want to save. You can use the framework to:
- store data permanently for offline use
- to cache temporary data or
- provide functionality like undo and redo for your apps.
Core Data is a combination of an object graph manager and a persistence framework. An object graph is the collection of the various objects in the model layer along with their relationships to one another and the rules that govern these relationships. This is part of what Core Data does for you – it manages the object graph.
But once you have instances of these objects in the graph, you also need to save, update and delete them based on all the user preferences and interactions. This is the second job of Core Data – to provide a persistence framework that handles that set of functionality.
With Core Data you don’t use plain Swift types to model your data – instead you use a managed object. A managed object looks and feels like a Swift class but you should think of it more as a representation of the data held in the persistent store. Instead of being a specific type, a managed object is a subclass of
NSManagedObject and is more like a generic container that we can store our data in – much like a dictionary.
When creating managed objects you can specify what kind of shape you want the data to take and Core Data provides a programmatic interface to interact with the underlying generic container. Instead of creating objects directly in code, Core Data provides a visual interface to define the types that you’ll use to represent your data. Under the hood Core Data doesn’t actually create an actual type – just a generic container that uses keys and values to store data. It would be a pain though if that’s how you had to interact with the object, not to mention very error prone. Instead Core Data provides an interface for you that restricts access to the underlying data using properties on the subclass.
Since these are generic containers, when creating an instance of these types you use an entity description which specifies an entity’s name, properties and the class that represents it. This object is then used to keep the convenience code that Core Data has created for you and the underlying stores in sync. You won’t worry about this part too much though because you won’t be interacting with the entity descriptions directly.
Managed Object Context
As a user interacts with the app and modifies the data model, you need a way to keep track of all the changes. This is where the next part of the stack comes in – the managed object context. Of the entire Core Data stack, the managed object context is the one that you’ll interact with the most. As a result, it’s the only object that you’re going to expose to the rest of the app when you create your stack later.
Think of the managed object context as an intelligent scratchpad. When using a real scratchpad you keep notes by adding, modifying, and striking out text on the page. In the same way the context keeps track of everything that changes across the object graph layer. It’s the context’s job to keep track of all these changes that occur. The changes are not persisted until you save the data.
You must register all managed objects with a managed object context; otherwise you can’t use them. The context inserts it appropriately into the object graph, and ensures that the model layer is in a valid state. The managed object context handles most of the how and where of saving data for you.
Persistence Store Coordinator
So far you know that Core Data represents models using Entities as managed object models. You also know that it creates these inside of a managed object context to create the object graph. As you modify the graph, the context keeps track of these changes. The next part in the stack is the persistent store coordinator; it sits in the middle of the stack, between the managed object context and the underlying persistent store and facilitates communication between the two.
While the context is responsible for keeping track of changes made to copies of the managed object model, it’s the coordinators job to create instances of the actual entities defined in the model.
To bring it all together:
- the managed object model defines the structure of the data, and
- the persistent store coordinator realises objects from the data in the persistent store and passes those objects off to the requesting context.
Jelly Belly – Update
With the updates I made to the app in the last few weeks, we were able to retrieve data from an API and this time we were able to save the data and changes in the app. The API used is a bit limited and I had to map some of the information coming from the API to my existing data model . The end result is a dish menu that is populated with dishes coming from the API – the data is unfortunately a bit dirty and there are a number of duplications… In any case, the Menu now looks like this
Finally I have used the same information to save a simplified version of the data model into Core Data and use that to present a new tab called
Specials where the user can see the Specials in the menu, ordered by cost and name and is able to add tags. These tags are also persisted in the app.
Also published on Medium.