0% found this document useful (0 votes)
15 views1 page

CoreData Using Generics and The Singleton Design Pattern - by Gianluca Annina - Medium

How to use generics with Core Data

Uploaded by

afonjajim
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
15 views1 page

CoreData Using Generics and The Singleton Design Pattern - by Gianluca Annina - Medium

How to use generics with Core Data

Uploaded by

afonjajim
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 1

Search Write Sign up Sign in

CoreData using Generics and the


Singleton design pattern
Gianluca Annina · Follow
3 min read · Feb 7

516

Do you need to store information locally on your device? If the answer is


affirmative and the data are too big for UserDefault then you will probably
need to use CoreData.

What is, then, the most efficient way to use CoreData? Let’s take a look at
what Xcode suggests us to do when creating a new project importing
CoreData.

Checking this box will create a whole project ready to be used with examples
of how to use CoreData with different useful functions already implemented.

Most important it will generate the “Data Model” file and the
“PersistenceController” struct. Let's take a deeper look at this struct.

1 import CoreData
2
3 struct PersistenceController {
4
5 static let shared = PersistenceController()
6
7 static var preview: PersistenceController = {
8 let result = PersistenceController(inMemory: true)
9 let viewContext = result.container.viewContext
10 for _ in 0..<10 {
11 let newItem = Item(context: viewContext)
12 newItem.timestamp = Date()
13 }
14 do {
15 try viewContext.save()
16 } catch {
17 // Replace this implementation with code to handle the error appropriately.
18 // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful dur
19 let nsError = error as NSError
20 fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
21 }
22 return result
23 }()
24
25 let container: NSPersistentContainer
26
27 init(inMemory: Bool = false) {
28 container = NSPersistentContainer(name: "CoreDataTutorial")
29 if inMemory {
30 container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
31 }
32 container.loadPersistentStores(completionHandler: { (storeDescription, error) in
33 if let error = error as NSError? {
34 // Replace this implementation with code to handle the error appropriately.
35 // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful
36
37 /*
38 Typical reasons for an error here include:
39 * The parent directory does not exist, cannot be created, or disallows writing.
40 * The persistent store is not accessible, due to permissions or data protection when the device is locked.
41 * The device is out of space.
42 * The store could not be migrated to the current model version.
43 Check the error message to determine what the actual problem was.
44 */
45 fatalError("Unresolved error \(error), \(error.userInfo)")
46 }
47 })
48 container.viewContext.automaticallyMergesChangesFromParent = true
49 }
50 }

AutoGeneratedPersistanceController.swift hosted with ❤ by GitHub view raw

As it’s possible to notice the “PersistenceController” retrieves the


information of the container and its context, then it uses the
“@EnvironmentObject” to pass the retrieved context to every View.

1 import SwiftUI
2
3 @main
4 struct CoreDataTutorialApp: App {
5 let persistenceController = PersistenceController.shared
6
7 var body: some Scene {
8 WindowGroup {
9 ContentView()
10 .environment(\.managedObjectContext, persistenceController.container.viewContext)
11 }
12 }
13 }

AutoGeneratedAppFile.swift hosted with ❤ by GitHub view raw

This kind of approach doesn’t take full advantage of the Singleton design
pattern and makes the code messy.

A better way to use CoreData


A better approach would be to use the “PersistenceController” to also handle
the different operations, maybe using different extensions of the struct to
keep the different files tidier.

Initially, the “PersistenceController” will be simple and without any function


except for the private initialiser.

1 class PersinstanceController{
2
3 static let shared = PersinstanceController()
4
5
6 let container = NSPersistentContainer(name: "ContainerName")
7
8 private init(){
9
10 container.loadPersistentStores{ description, error in
11
12 if let error = error {
13
14 print("Core Data failed to load: \(error.localizedDescription)")
15
16 //Handle the error correctly
17
18 }
19 }
20 }
21 }

CustomGeneratedPersinstanceController.swift hosted with ❤ by GitHub view raw

Now we can create the functions that implement the generics, in detail
“fetch” and “delete”

The “fetch” function is simple, it takes as a parameter the name of the entity
and the type, using them it retrieves all the values stored in the table.

1
2 func fetch<T:NSFetchRequestResult>(entityName:String) throws -> [T] {
3
4 let request = NSFetchRequest<T>(entityName: entityName)
5
6 let entities = try container.viewContext.fetch(request)
7
8 return entities
9
10 }
11
12 let foodArray:[FoodEntity] = try PersistenceController.shared.fetch(entityName: "FoodEntity")

GenericFetch.swift hosted with ❤ by GitHub view raw

Be careful: when using the generics in this way since you always have to
declare the type of your variable, otherwise the function will not understand
from what table you need to fetch data.

1
2 let foodArray:[FoodEntity] = try PersistenceController.shared.fetch(entityName: "FoodEntity") // Works because you pointed out the type
3
4 let foodArray = try PersistenceController.shared.fetch(entityName: "FoodEntity") // Doesn't work since it doesn't know the type you need to use

UseOfGenerics.swift hosted with ❤ by GitHub view raw

The “delete” function is even simpler and just needs, as a parameter, the
element you want to delete.

1 func delete<T:NSFetchRequestResult>(data:T) throws{


2
3 container.viewContext.delete(data as! NSManagedObject)
4
5 try saveContext()
6
7 }
8
9 try PersistenceController.shared.delete(data: food)

DeleteGenericObject.swift hosted with ❤ by GitHub view raw

The “saveContext” function it’s used to save the changes made when
deleting/adding/editing an object.

1 func saveContext() throws{


2
3 try container.viewContext.save()
4
5 }

SaveContext.swift hosted with ❤ by GitHub view raw

Unfortunately, it’s not possible to completely integrate the generics


mechanism with the creation of a new element. The basic function is the
following:

1 func createNewFood(product:Product) throws{


2
3 let newFood = FoodEntity(context: container.viewContext)
4
5 product.copyInEntity(food: newFood)
6
7 try saveContext()
8 }
9
10 try PersistenceController.shared.createNewFood(product: Product(name: "TestFood", expiryDate: Date(), isOpened: false, category: .meat))

CreateNewFoodCoreData.swift hosted with ❤ by GitHub view raw

Now you are probably asking yourself: “What are Product and the
copyInEntity functions?”

Product is the struct that encapsulates all the pieces of information retrieved
from CoreData and handles them inside the view.

It is declared this way:

1 import Foundation
2
3 struct Product: Identifiable, Hashable {
4 var id = UUID()
5 var name: String
6 var dateCreated = Date()
7 var expiryDate: Date
8 var isOpened: Bool
9 var category: Category
10
11 init(name: String, dateCreated: Date = Date(), expiryDate: Date, isOpened: Bool, category: Category) {
12 self.name = name
13 self.dateCreated = dateCreated
14 self.expiryDate = expiryDate
15 self.isOpened = isOpened
16 self.category = category
17 }
18
19 init(food:FoodEntity) {
20 self.name = food.name ?? ""
21 self.dateCreated = food.dateCreated ?? Date()
22 self.expiryDate = food.expiryDate ?? Date()
23 self.isOpened = food.isOpened
24 self.category = Category.getCategory(category: food.category ?? "")
25 self.id = food.id ?? UUID()
26 }
27
28 func copyInEntity(food:FoodEntity){
29 food.name = self.name
30 food.category = self.category.name
31 food.isOpened = self.isOpened
32 food.expiryDate = self.expiryDate
33 food.dateCreated = self.dateCreated
34 food.id = self.id
35 }
36 }
37
38 enum Category: CaseIterable {
39 case meat
40 case fish
41 case vegetables
42 case fruit
43 case others
44
45 var name: String {
46 switch self {
47 case .meat:
48 return "Meat"
49 case .fish:
50 return "Fish"
51 case .vegetables:
52 return "Vegetables"
53 case .fruit:
54 return "Fruit"
55 case .others:
56 return "Others"
57 }
58 }
59 static func getCategory(category:String)->Category{
60 if category == "Meat"{
61 return .meat
62 }else if category == "Fish"{
63 return .fish
64 }else if category == "Vegetables"{
65 return .vegetables
66 }else if category == "Fruit"{
67 return.fruit
68 }else if category == "Others"{
69 return .others
70 }
71 return .others
72 }
73 }
74
75
76
77

Product.swift hosted with ❤ by GitHub view raw

Inside the struct are defined two functions that help to exchange data
between the swift object and the CoreData object:

the custom init takes as a parameter a CoreData object and assigns all the
values to the swift one;

the copyInEntity does the exact opposite, assigning to a CoreData object


all the values of the swift one.

These two functions are useful in order to clean the code and handle the
code in a faster way.

If you want to check the original project here is the GitHub link:
https://github.com/SidusProxy/CoreDataTutorial

Swift Core Data IOS App Development Xcode Swiftui

516

Written by Gianluca Annina Follow

68 Followers

I am a computer science and Apple Developer Academy student. Linkedin:


https://www.linkedin.com/in/gianlucaannina/

More from Gianluca Annina

Gianluca Annina Gianluca Annina

API calls using Swift async/await How to link your GitHub account to
and error handling Xcode
Are you trying to create a new application To link your GitHub account first of all you
using some API calls in Swift but you don’t… need to configure it on your Mac. Open the…
know where to start? This tutorial guides terminal (cmd + spacebar and type
3 min read · Feb 14
you… 3 min read · and…
“terminal”) Feb 5

324 306

Gianluca Annina Gianluca Annina in Better Programming

Use Swift Actor to handle APIs Build a Basic Server Side Swift
calls Application With Vapor
In this tutorial we will explain what an actor is Design a university’s exam system
and how to use it to handle APIs calls.

2 min read · Apr 1, 2022 3 min read · Mar 24, 2022

310 2 311

See all from Gianluca Annina

Recommended from Medium

Amit Srivastava Gurjit Singh

CoreData, CloudKit integration in Getting Started with SwiftData


SwiftUI a visual guide There are lot of frameworks introduces on
CloudKit framework allows users to access WWDC23. SwiftData is one of them. SwiftDa…
and sync data in their iCloud containers with… designs to persist data using Swift code. You
the various devices that are using the same can…
6 min read · Aug 2
iCloud… 3 min read · Aug 10

14 1

Lists

Staff Picks
541 stories · 559 saves

Gerald Brigen Naresh Kukkala

Modelling Schema with SwiftData: “SwiftUI and Core Data”. How Core
A Comprehensive Guide Data can be used with SwiftUI to…
Introduced at WWDC23, SwiftData is a store data
Today, let’spersistently
delve into an impactful
powerful and expressive persistence… combination for app developers—SwiftUI a…
framework built for Swift. It allows developers Core Data. This merging of a versatile…
4
tomin · Jul 6
read their…
model 2 min read · Nov 25

10 1 2

Geor Kasapidi in Better Programming Mia M

Mastering Thread Safety in Swift SwiftData Fix: Failed to find any


With One Runtime Trick currently loaded container for…
The optimal method to ensure memory safety Model
This is a common error I was running into
in a multi-threaded environment upon creating new SwiftData models, even…
though I was doing all of the set up correctly
4 min read · Aug 14 · 2 min read · 5 days ago
for the…

219 1 3

See more recommendations

Help Status About Careers Blog Privacy Terms Text to speech Teams

You might also like