Sharing a Core Data Model with a Swift Framework — Updated to Swift 5.1 & Xcode 11
In this tutorial I will show you how to create and use a Framework with a Core Data model, Why a framework you may ask, well here is why
A framework is a hierarchical directory that encapsulates shared resources, such as a dynamic shared library, nib files, image files, localized strings, header files, and reference documentation in a single package.
Multiple applications can use all of these resources simultaneously. the system loads them into memory as needed and shares the one copy of the resource among all applications whenever possible.
This tutorial consist of 4 sections
- Creating the framework
- Creating our data model using core data
- Creating the core data Manager class
- Using it in a separate App
Getting Started
Step 1 — Creating a Framework
- Open Xcode and create a new project, under iOS tab pick the Cocoa Touch Framework and click Next.
2. Name it CoreDataFramework select your Team if necessary, uncheck Unit Tests and click Next, Save it on your Mac and hit the Create button.
3. You now have created an empty framework template
Step 2 — Creating the Core Data Model
- Create a new file and choose the Data Model Template, give it the name CoreDataModel and save it inside the projects folder.
We now have an .xcdatamodeld which stands for “Xcode Core Data Model”
2. lets add an Entity by clicking the Add Entity plus button on the bottom, and name it Person
3. To that Entity we will add the following attributes, firstname and lastname of type String and age of type Integer16
We are now done with the core data model creation.
Step 3— Core Data Manager
Ok lets write some code
Create a new swift file and name it CoreDataManager and copy the following code, ill explain every step of the way
//
// CoreDateManager.swift
// CoreDataFramework
//
// Created by Yoel Lev on 24/01/2019.
// Copyright © 2019 Yoel Lev. All rights reserved.
//import Foundation//1.
import CoreDatapublic class CoreDataManager {
//2.
public static let shared = CoreDataManager()//3.
let identifier: String = "com.yoelev.CoreDataFramework" //Your framework bundle ID
let model: String = "CoreDataModel" //Model name
}
- We first import CoreData framework,
- Then we create a public class which is a Singleton
Notice that i gave a public access control to every instance/property/ function that we would like to access through our custom framework, the default is internal, hence we wouldn't be able to access it.
3. Copy your framework bundle identifier string into the identifier variable as well as your .xcdatamodeld file name to the model variable
4. Next we create our NSPersistentContainer closure which simplifies the creation and management of the Core Data stack by handling the creation of the managed object model.
Copy the code below to our CoreDateManager class
// 4.
lazy var persistentContainer: NSPersistentContainer = {
//5
let messageKitBundle = Bundle(identifier: self.identifier)
let modelURL = messageKitBundle!.url(forResource: self.model, withExtension: "momd")!
let managedObjectModel = NSManagedObjectModel(contentsOf: modelURL)
// 6.
let container = NSPersistentContainer(name: self.model, managedObjectModel: managedObjectModel!)
container.loadPersistentStores { (storeDescription, error) in
if let err = error{
fatalError("❌ Loading of store failed:\(err)")
}
}
return container
}()
5. Now we need to get our managedObjectModel from our custom framework, so we explicitly tell our app from which bundle we should retrive it by using the bundle identifier and model name.
6. Then we initialize our NSPersistentContainer with the model name and managed object model.
Create & Fetch — Lets give that Person a name
Copy both createPerson() & fetch() function into the CoreDateManager just under our persistentContainer clousre.
public func createPerson(firstname: String, lastname: String, age: Int16 ){
let context = persistentContainer.viewContext
let contact = NSEntityDescription.insertNewObject(forEntityName: "Person", into: context) as! Person
contact.firstname = firstname
contact.lastname = lastname
contact.age = age
do {
try context.save()
print("✅ Person saved succesfuly")
} catch let error {
print("❌ Failed to create Person: \(error.localizedDescription)")
}
}public func fetch(){
let context = persistentContainer.viewContext
let fetchRequest = NSFetchRequest<Person>(entityName: "Person")
do{
let persons = try context.fetch(fetchRequest)
for (index,person) in persons.enumerated() {
print("Person \(index): \(person.firstname ?? "N/A") \(person.lastname ?? "N/A") Age:\(person.age )")
}
}catch let fetchErr {
print("❌ Failed to fetch Person:",fetchErr)
}
}
By calling createPerson we will add a new person object and save it into our core data model.
fetch() will retrieve all of our saved context from our core data model.
Notice that both function are made public so we can access them though our framework in our Contacts App which will create later
You should now successfully build your project
Core Data Manager class overview
Lets extract our framework for later use
In the frameworks project navigator under the Products folder right click the CoreDataFramework.framework and select show in finder, copy the framework to the Desktop for now as we will use it in a jiffy.
Step 4 — Use our Core Data Framework in a seperate project
- Create a new iOS Single View App and name it Contacts,
- From the project navigator, right click the project name select Add Files to “Contacts”
3. Browse to your desktop and select the CoreDataFramework.framework we saved earlier, tick the “copy items if needed” checkbox to copy the file into your projects folder.
4. Navigate to your project Target, in the General tab go to Embedded Binaries and add the CoreDataFramework, make sure to remove the duplicated framework in the Linked frameworks and Libraries.
You should now successfuly Build your project
Copy the following code to ViewController.class
override func loadView() {super.loadView()CoreDataManager.shared.createPerson(firstname: "John", lastname: "Doe", age: 35)CoreDataManager.shared.createPerson(firstname: "Liam", lastname: "Croft", age: 27)CoreDataManager.shared.createPerson(firstname: "Oliver", lastname: "Twist", age: 15)CoreDataManager.shared.createPerson(firstname: "Luke", lastname: "Skywalker", age: 70)}override func viewDidLoad() {super.viewDidLoad()CoreDataManager.shared.fetch()}
Select your preferred iPhone simulater, Build & Run
You have successfully created and shared your custom core data framework
Let me know if you are interested in part 2 of this tutorial which will show you how to build a framework in a production way, so you can ship it to the App Store, and not just run it in a simulator.