Creating an abstraction layer for the model
Why another model?
I’m using Core Data to store the data in our app Remember. To create a Core Data model, I need to inject a
NSManagedObjectContext object in the
NSManagedObject constructor. The problem is I don’t want to have to pass around the context object everywhere in the app. I want it to be isolated in the model layer. And I want to manipulate simple POSOs (Plain Old Swift Object) in the business layer.
Also, my database objects should not know my business objects. By doing so, I could easily replace Core Data with another database provider, without impacting the rest of the codebase. This idea is inspired by the Clean Architecture.
Business and model layers
In our app Remember, I only have one table to store the last times a user did something. Pretty simple.
I created an
Event class in my business layer. This is the object I will manipulate in the views.
For the model layer, I created an
EventManagedObject class, which inherits from
To convert the objects in both directions, I created an
ObjectConvertible protocol, implemented by the
Thanks to the protocol extension, I have only two methods left to implement. Those are the methods that transfer the business object’s data to the database object’s data and vice versa.
It is now super easy to perform operations on the
Event object, without manipulating
NSManagedObject objects directly.
At the beginning of this article, I said I didn’t want to have to pass a
NSManagedObjectContext object throughout the code.
To isolate the context, I created an
EventStore class, which keeps a reference on the
Even though this method provides some comfort when working with model objects, it has some downsides.
The biggest one is I can’t use Core Data’s built-in lazy-loading system or NSFetchedResultsController. If I wanted to use it, I would have to create my own pagination system.
Dealing with relationships is also not implemented in this solution. Even though I didn’t investigate it, the conversion of the nested objects would probably be in the
from(object: T) and
toObject() -> T implementation methods.
I managed to do what I initially wanted, the
Event class is totally agnostic of the
I’m manipulating simple objects in the views.
And the model layer is isolated from the rest of the application. I could definitely replace Core Data with another database provider, without impacting the rest of the codebase.
The only thing left is to handle Core Data errors. Something I will definitely do in the app.
I honestly never worked on an app that had an abstraction layer for the model. As I said, it’s not common in the iOS world, from my experience at least. But I’m super happy with the result and I will definitely use it in my side project Remember.
Any feedback is welcome!
A big thank you to Ayrton for his help.