Codable Coredata MVVM

Nithin Kumar
12 min readApr 5, 2020

--

This is a simple article to learn How to use Codable protocol and Coredata for local storage together. Very basic knowledge on Codable protocol and Coredata is mandatory to understand this. But don’t worry, I will try to explain some basics too. Also we will have some insight on MVVM design pattern along with this to understand the application architecture.

Here in this tutorial I will be using xcode 11.1 and simulator with iOS 13. Please try to use the same for learning purpose.

Create a new project and name it “CodableCoredata” and don’t forget to check “Use Core Data” option

In this application we populate a list of Persons with their name and person id. Later we may add Address details like City, State and country to show parsing nested json.

First delete the ViewController.m and viewcontroller in Storyboard as we need UITableViewController to populate the list.

Make the project structure like below. Add “PersonViewController” Subclass of UITableViewController and a “PersonCell” Subclass of UITableviewCell.

Add a Table controller in Storyboard & assign PersonViewController in Inspector Tab and Embed this into UINavigationController. Also assign PersonCell in Table with Resuse identifier as “PersonCell”

Add labels for displaying Name, Id, City, State and country in Cell and make Connections. Check story board connection & Constraints for more details.

As we are also Going to Use MVVM design pattern I will just make a basic walk through for the same only for the parts relating to our implementations. Then finally go in details about Codable and Core Data together.

At this point we are just ready with the UI to Display.

Now we need Two ViewModels to fetch and manage the content. Here Fetch means just parsing a local json.

1. PersonListViewModel to parse and manage Person list.

2. PersonViewModel to modify data for person while displaying if necessary.

Add these to View Models and make sure it inherits from NSObject.

Now open PersonListViewModel.Swift and paste the following json string.

This represents a json string which we are going to use in this app. We will replace it with a nested json later with slight modification to showcase a technic to use in creating model.

Now we have the json ready. We will create Model called Person, conforming to Codable protocol and add properties as per the json and looks like below.

Now add the below function inside PersonListViewModel.swift.

What it does?

It simply use content json to decode into Person Model. To test this add PersonListViewModel().parsePersonJson() in viewDidLoad() function present in PersonViewController.swift.

Run the app and you should be able to see below output.

All good till here?

NOW the Topic of the day… Core Data with Codable

Now it’s time to Jump into core data stuff! Hope you know what core data is and its basics. We already have Core Data added in project while creating the Project and CodableCoredata.xcdatamodeld Datamodel is already present in Bundle. We have its implementation in AppDelegate.swift which we will shift into a utility class to make a clean implementation, add any functionalities if required.

Add “Persistence” folder inside “Utility” folder added earlier.

Now add a new file inside Persistance folder and name it “CoreDataStorage” and subclass of NSObject.

Cut persistentContainer var and saveContext() method in AppDelegate.swift and paste it inside CoreDataStorage.swift class just added.

Add below code inside the same class to make it Singleton as we may need to access throughout in the app.

To access the NSManagedObjectContext (Hope you know what it is. If you don’t know please refer to any Core Data tutorial) of core data, we add the following method in CoreDataStorage class.

We add one more helper method to same class for deleting all contents of any Entity (Table in sql term). Add the below method.

Now if you go SessionDelegate.swift you see the error for calling saveContect() method. Delete the line and add below line in that place.

CoreDataStorage.shared.saveContext()

Now we are almost ready. Now time to create entity in DataModel & add Attributes (Columns in sql term) to the entity.

Open CodableCoredata.xcdatamodeld in Project navigator and click on add entity. Rename the entity as “Person” because we have Person model already created.

Now add attributes id and name both of type String.

Now the Datamodel should look like below image.

Now to use Person model as NSManagedObject for entity we added now, We should import Coredata and change the Person from Struct to Class and the make it inherit from NSManagedObject class.

Also to link attributes with variables in model class add @NSManaged keyword to all variables and change all let to var if any.

Add below code just below the variable declared. We need this to access coding keys for decoding and encoding. Also we should use it when json has lot of key and we need only few of them.

Add init(from decoder: Decoder) and encode method to conform to encodable and decodable methods and make it ready to use as Coredata model.

We will not use encode method though in this demo app, as we are just decoding json and save it in Core Data and display. For demo I will just write code to show how to use this method.

Add below code inside encode method.

Before we write any code inside init(from decode: Decoder) method, we need a key to access codingInfoKey which is used for storing and accessing managedObjectContext To/From Decoder.

Go to Utilities and create folder named Extentions. Now add new swift file inside this folder and name it as CodingUserInfoKey+Util.

Add the below code in the added file.

This extension is used to fetch the managed object context while decoding.

Now Jump to Person Model class and replace init method with below code.

If you see any mis alignment and error due to this. Dont panic. Press control+A to select all and Control+I.

Note: If you see any error as duplicate declaration of Person then just do a Product -> Clean.

Now our Model class is ready for decoding and save the decoded values into core data. Its not over yet. We need to configure our decoder to save to Core Data while decoding :)

Before even start decoding we need to make some settings as manually creating Model class for core data. Follow the below steps.

Click on the Person entity created -> open inspector -> click on last TAB (Cylindrical)

Set the Module as — Current Product Module

Set Codegen to — Manual/None

This is to restrict core data from creating own Model class for particular entinty.

Now open PersonListViewModel.swift file and replace parsePersonJson() function with below code.

Now Run the App and see it runs without errors. YAY!!!

Now you can see the logs printed in console. There entities are printed with attribute values and the path for Document folder is also printed in console.

Go to that path in finder. You see a empty Documents Folder. Below that you see Library folder. From there navigate as per the below mentioned path.

Library -> Application Support -> CodableCoredata.sqlite

Browse this DB using DB manager app or Firefox plugin or any DB browser you are comfortable with.

You will see that all data from the json is saved into Coredata :)

Next we will use Nested Json. But First let us populate the data on simulator/device.

In MVVM we can use View model for calling a webservice and getting data. In here we don’t make any Network calls but we just parse a Json that we formed inside ViewModel itself.

I will not go in details with MVVM as this tutorial is to learn using Codable protocol with Core data.

So let us now begin our work to display these contents with MVVM Design Pattern.

If not interested in MVVM you simply jump to the section Nested json + Single model below.

We need to bind obtained data into View. So we use Delegate pattern here to bind data. Once parsing is over we call Success method through delegate and Failure method if Decoding failed in this case.

Open PersonListViewModel.swift and Add below code Just below the Import Statements.

Now Add below lines just below the class declaration.

Here we are using dependency injection and passing the delete parameter in “init” method itself to avoid the situation of forgetting to set delegate also to keep the code clean whichever class we create the instance of this ViewModel.

Now add “self.persons = result” in parsePersonJson() method just below line let result = try decoder.decode([Person].self, from: responseData)

Now parsePersonJson function should look like this.

Good so far? Now we need to bind the values to UI. So to let the Viewcontoller to know that parsing is done, we have created the protocol. And call these Delegate methods once parsing is success or fail.

We are assigning the result to persons array. We will not call delegate method immediately instead we make use of observers provided by swift :)

Replace the private var persons: Array<Person> with below code immediately after class declaration.

didSet is the observer called on any property when a value is set to that property.

Add below lines in catch block inside parsePersonJson function.

self.delegate?.parsePersonsFailedWithMessage(“Your error message!”)

We added the Person objects to the array and we don’t want to access model directly because sometimes we want to combine multiple values in model and display. But we don’t want ViewController to do the job. So we create another ViewModel to access each model values.

Add a class subclassing NSObject inside ViewModels Folder and name it PersonViewMode.

Add below code inside the class.

Now go PersonListViewModel.swift and add below functions after parsePersonJson Function.

Let us just create a UIViewController Utility to show the alert in case of any error Just to keep the code clean.

Right click on Extensions folder inside Utilities folder. NewFile -> Swift file

Name it as UIViewController+Util.

Delete import Foundation at the top and add below lines.

Now we need the PersonViewController to implement the PersonListViewModelDelegate methods and conform to this delegate.

Open PersonViewController.swift and create a extention comforming to this delegate. To do that Copy below code to end of the file.

Now we have the extension ready.

We will simply reload the table inside parsePersonsSuccess method and call show alert method inside method in case of error.

Added code should look like below.

Now in the same PersonViewController.swift add below code just above the viewDidLoad method and delete parsePersonJson() method call present.

var personListViewModel: PersonListViewModel!

And now instantiate the viewmodel, and call parsePersonJson method inside the viewDidLoad method like below and set Title.

Now Open PersonCell.swift and below method.

This method accepts PersonViewModel as a mandatory parameter. And setup the UI contents with available values in ViewModel.

Now open PersonViewController.swift again and replace UITableview Datasource methods with methods below which has required code to set Table contents.

Now run the app and you should be seeing the person id, names displayed like below.

I hope you know the basic of MVVM by now if had no idea about it.

We see that City, state and country are not set. We will be soon doing it with nested Json. I will show you how we can parse nested json into a single model. And also while encoding how we can encode it as a nested json again :) .

Keep following.

Now if you see the PersonViewController you see that you have a lot of code written which makes it Massive View Controller. To make it light You can move the Extension we added at the end to a separate file. And also we can move data source of Tableview into a separate file which makes it very neat. So lets do it now.

Create a new folder named Datasources inside the MVVM folder. Add a new swift file subclassing NSObject and name it PersonViewControllerTableDatasource and conform this class to UITableViewDataSource and add the below code inside the class.

Now You can add UITableViewDataSource protocol stubs but we will cut and paste datasource methods already present in PersonViewController class to PersonViewControllerTableDatasource class below init method.

We don’t need to have numberOfSection datasource method as by default it is 1 and we need only one section. So please remove that function.

Now you are already seeing error for override key word. No need to use that key word we are using separate class for data source. So remove override keyword for both methods.

Now our new datasource class should look like below.

Now open PersonViewController.swift and declare data source as below.

Now add the below code in ViewDidLoad method below the line where viewmodel is instantiated.

Now run the project on device or simulator. It successfully run and display the contents as expected :-)

Have a look at PersonViewController.swift :-). Looks very neat and not a Massive view controller anymore :-)

Here we end MVVM Concepts. But its not over yet. We are going implement nested json and will parse those into single model and save in coredata and display the contents :-). Let’s start this now. Follow the tutorial carefully You will like it from here.

Nested Json + Single model

Open PersonListViewModel.swift and replace contentJson string with following string.

Open Person Model and add the city, state, country variable to model and CodingKeys enum case. As these keys are in address key in json, Though we don’t need this address in model but we should add that in coding keys as we need to access this key to get access to city, state and country key in json.

Now the variable & enum in Person model should look like below.

Add below code in init(from decoder: Decoder) method

Here nestedContainer is being used. This is used because address is another dictionary that contains keys & values. We could create another model and parse into that model but here we don’t want to create a separate model and we want it to be part of Person model itself. nestedContainer will give access to the keys & values inside Address key which is again a container from which we can parse keys inside into the same model.

Now open PersonViewModel.swift and add below code which sets three more var’s city, state and country.

We should set these values in UI now. Open PersonCell.swift and add below code in configure method.

Open CodableCoredata.xcdatamodeld in Project navigator and click on person entity.

Now add attributes city, state and country of types String.

Now the Datamodel should look like below image.

Now run the app on simulator and see that all contents are displaying :-)

Go to the path printed and open sqlite in any DB Browser see the contents. You should be able to see the json contents saved in DB. If you can’t see check where you missed the flow in tutorial.

Now we move to encode part. Though we are not using encode functionality in this app, just for demonstration purpose to show how to use encode and encode the value into json format that received ie, nested json.

Open PersonListViewModel.swift and add below code in parsePersonJson() function just below code printing the document path.

Now run the App again and you can see that encoding is success and able to the encoded string printed in the console. To understand the pattern copy the string printed and paste in any online Json formatter. You should be able to see formatted json there.

See that it is a nested json where city, state and country are nested inside the address key.

Thanks for reading. Please find the completed project in GitHub.

This is the first time I am writing in Medium. Please share your thoughts and improvements required in this Article.

Thank you :)

--

--