Hello CoreData!
by Viktor Amelin, Senior iOS developer
Today we will review framework under the terrible name CoreData, from Apple. I hate it so much. This is Apple’s solution to work with SQLite (a relational database). CoreData can store Swift objects in SQLite, and also it can perform the reverse operation.
Introduction
I personally prefer the Realm, since you don’t need to do a lot of movements to make it work: simply install and begin to create all what you want, plus the official website has a great documentation for all features. But when you look through the vacancies of other companies (I personally never do it. Other companies… they exist? For real?!:)). Often you see, that CoreData is required, and if you do not have experience with this framework, then you can easily became «gone with the wind» at the beginning of the interview, and nobody well ever know all about those beautiful buttons you can do :).
So why do I don’t like this framework? Because it is heavy for the understanding for the beginners, and it is easy to get confused and make mistakes, and the more code you have written, the more likely that somewhere you could be wrong.
Starting with ios 10, Apple have done much to facilitate the work with CoreData. For example, they’ve presented NSPersistentContainer
object, that takes over the task of creating NSManagedObjectModel
, NSPersistentStoreCoordinator
and NSManagedObjectContext
. Now for getting started you just need to to initialize the persistentContainer = NSPersistentContainer(name: "MyModel")
object. At the beginning this article was intended as a review of third-party solutions for the CoreData, but since Apple has altered this framework, many of those solutions were either in the remaking process or worse — they were written in Objective-C. So we will have three examples. In the first one we’ll go through NSFetchedResultsController
and NSPersistentContainer
; in the second, we will begin to write the easy-to-use class, and in the last example we'll improve the class by adding generics. .
Example 1
The project is available for study and called MagicalRecord_project
(originally I wanted to use this framework). Let's view the Model.xcdatamodeld
file:
For avatar
attribute (of Binary Data
type) an option Allows External Storage
was turned on..
Let’s move to the controller:
Here we create persistentContainer
and fetchedResultsController
objects, which will be responsible for the filling with the data. Also, we'll create a method that will help us to create objects:
Watch how it all looks in viewDidLoad
:
This line perform(#selector(insertAfterDelay), with: nil, afterDelay: 2.0)
adds a third object to the context, and NSFetchedResultsController
updates tableView
(we'll talk about it later).
fetchedResultsController.performFetch()
transmits data from CoreData to the controller.
Now run this app.
At the beginning we see two added object, and after two seconds — three. Let’s create an extension
for ViewController
:
Since we have fetchedResultsController
instead of dataSource
array, we use it to obtain all the necessary data. The variable fileprivate lazy var fetchedResultsController
we've declared ourselves a delegate of NSFetchedResultsController
. Now we gonna make the necessary methods:
Now, when something changes (by adding, updating, or deleting some element), NSFetchedResultsController
knows about it and can make the necessary corrections in UITableView
. Such kind of mechanism is implemented in the Realm:
It ain’t suits with our example, but as you can see, the UITableView
update mechanisms are similar.
Example 2
In this example we will create StoreManager
. Open StoreManager_project
project. StoreManager
was created using Singleton
pattern (one copy for the life of the program):
NSPersistentContainer
has two properties, more specifically, the property and method: viewContext
and newBackgroundContext
. The first is associated with the main queue
, the second with privateQueueConcurrencyType
. When we write something in newBackgroundContext
, it sends a notification for viewContext
object to merge content. Therefore, it appears that we no longer need to subscribe to this notification. From viewContext
documentation:
This context is configured to be generational and to automatically consume save notifications from other contexts.
Due to newBackgroundContext
:
…is set to consume NSManagedObjectContextDidSave broadcasts automatically.
I’ve added a few methods to modify in third example:
First, we clean the storage and then add the car models. Then there is a method to add a third car, after two seconds (never use performSelector: afterDelay:
— it is a bad practice). And two methods showMainStorage()
, which shows how the database has changed. For example, you can uncomment the following piece of code:
You can experiment with the notification of the database change. My result:
Example 3
In this example, I wanted to demonstrate how to work with JSON. Of course, in a real project I would use something for mapping, SwiftyJSON for simplicity, maybe. But for a little lesson, I requested JSON as a string and then parsed it:
And in the StoreManager
file:
Here I keep backgroundContext
as a variable to always get the only one backgroundContext
, which afterwards I can save by saveContext(type:)
method. Other methods are clear to understand. Since we have an enum
...
enum ContextType {
case main
case background
}
…we always know the context we’re working with. Let’s go back to the ViewController
. Notice how I create objects:
But there’s no context in insert(entity:)
method! The thing is, that I wrote extensions to work with generic data.
So you can add entity in context using its type and self (Car.self)
. Also the fetchAll
method to work with generics war added. We use it in StoreManager
methods. Now our manager is ready to go. I hope to test and improve it if needed.
Need assistance with building native iOS app? Feel free to contact us at info@stfalcon.com. Turn your brilliant business ideas into reality with Stfalcon team!
Originally published at stfalcon.com.