The Model Controller

I’ve uploaded this to a new repository, which will be used for the greater purpose of reusable FUMVC abstractions. This is the 1st contribution to FUMVC, so the library is currently really small.

The ModelController shouldn’t try to everything, if it’s primary purpose is to be highly reusable. I’ve kept the code to a minimum for this reason.

I usually use conventionally verbose Apple influenced function names, such as something like addDataStorageEntry . Yet lately I’ve been influenced by my work in React apps and its naming that seems to be influenced by intermediate operations — which seems to be the naming conventions that Apple are moving to as well. So the functions are defined as:

add(type:)

total(type:)

fetch(type: predicate: sort:)

save()

delete(by objectID:)

delete(type: predicate:)

What the sample code in this blog post doesn’t do — it only uses one managed object context (the view context used for the main thread), and it doesn’t implement thread handling, as it would detract away from the main topic. Although I have updated the Github repository with some thread handling, and cover it a little bit below. But for now, let’s dive into each of the above functions…

The ModelController properties just consists of an NSPersistentContainer , and 2 NSManagedObjectContext s for the main thread and a background thread.

There is a convenience initializer with a single purpose to set the model name via dependency injection instead of being coupled to the Core Data abstraction. The NSPersistentContainer is lazy because of this. The private modelName ’s default value should set the model name to the bundle, a likely safe scenario should you opt for the designated initializer. The modelName is set via the convenience initializer rather than a setter, because its single purpose it to be needed on instantiation and nowhere else.

The ModelController+Add takes care of the creation of a new NSManagedObject subclass. If Recipe is one of your model entities, you can use it by modelController.add(Recipe.self) .

I’ve included a total function as well as a fetch function in ModelController+Fetch , as they’re both fetch related. This is where your NSFetchRequest s are done, and the predicate strings and sort descriptors are optional, as you might want to use fetch to simply retrieve all records.

How to use total and fetch:

let total = modelController.total(Recipe.self) let predicate = NSPredicate(format: "name LIKE %@", "Fetcheroni Pizza")

let fetched = modelController.fetch(Recipe.self, predicate: predicate)

The ModelController+Save is pretty standard. Even if you don’t use a Core Data abstraction, it’s very likely that you’ve written a save() method to check for hasChanges and wrap a try/catch.

Finally, the ModelController+Delete . There are 2 delete methods here — one with the standard interface pattern used in the fetch method, with the type and predicate passed in to find the object you want to delete.

The other checks for the NSManagedObjectID , which is an issue that is consistently overlooked in deleting Core Data objects. Accessing the object via a fetch is no guarantee that the same object will be deleted on the same thread that it was accessed on, so deleting by ID is the recommended approach by Apple. The predicate method also wraps the delete(by objectID:) method for this reason.

How to use: