Core Data Master Course
Entity = table
attribute = field
When coding:
import CoreData
You can get CodeGen (click on the inspector of the entity) to manual/none.
When you do that, the type for each row in the database is NSManagedObject
Editor - create NSManagedObject subclass
If you edit an attribute, remember to clean the project
Accessing the data
As a class variable:
var managedObjectContext = NSManagedObjectContext()
Getting today's date (with only day, month and year) and convert to NSDate to be stored in database
func getTodaysDate() -> NSDate
{
let dc = Calendar(identifier: .gregorian).dateComponents([.day, .month, .year], from: Date())
var dct = DateComponents()
dct.day = dc.day
dct.month = dc.month
dct.year = dc.year
let theNewDate = Calendar(identifier: .gregorian).date(from: dct)
let returnDate = theNewDate! as NSDate
return returnDate
}
attribute = field
When coding:
import CoreData
You can get CodeGen (click on the inspector of the entity) to manual/none.
When you do that, the type for each row in the database is NSManagedObject
Editor - create NSManagedObject subclass
If you edit an attribute, remember to clean the project
Accessing the data
As a class variable:
var managedObjectContext = NSManagedObjectContext()
When calling on the datasource, for instancing, in view did load:
let appDelegate = UIApplication.shared.delegate as! AppDelegate
managedObjectContext = appDelegate.persistentContainer.viewContext
Loading the data into a table
var results = [Grocery]()
let request: NSFetchRequest<Grocery> = Grocery.fetchRequest()
let request: NSFetchRequest<Grocery> = Grocery.fetchRequest()
do
{
results = try managedObjectContext.fetch(request)
groceries = results
tableView.reloadData()
}catch{fatalError("Error in retrieving grocery item")}
Storing the data:
let theGrocery = Grocery(context: self.managedObjectContext)
theGrocery.item = itemStringYouWantToStore
do
{
try self.managedObjectContext.save()
}catch{fatalError("Error in storing data")}
//call function to load data again so as to refresh table
self.loadData()
Accessing the data:
//individual NSManagedObject inside the array groceries:
let grocery = self.groceries[indexPath.row]
//getting the value of the item attribute from each grocery object
cell.textLabel?.text = grocery.item
Adding images to the entity
Binary data type (can be image, pdf, etc)
Allow external storage
Relationships
If there is a relationship between entities:
Let's say there is a relationship between Home and Sales History.
Add a relationship to Home - type: Sales History.
Add a relationship to Sales History - type Home.
Let's say that one home can have many sales history and one sales history can only have one home.
Go to home and select the relationship. Change the relationship type to 'to many'.
The Sales History will be a property of type NSSet in Home.
Subclass:
I have three entities:
Home, Condo and SingleFamily.
Condo and SingleFamily are subclasses of the Home.
Both Condo and SingleFamily have attributes inherited from Home.
However, I do not need to create these attributes in Condo and Single Family.
Set the parent entity to be 'Home' for both the Condo and Single Family.
Inspecting relationships
You can see the graph of the relationships by clicking on the 3 rectangle diagram at the bottom right hand side of the screen.
Check that the entities are empty, making sure that it is not populated again.
In AppDelegate.swift:
func checkDataStore()
{
let request: NSFetchRequest<Home> = Home.fetchRequest()
let moc = self.persistentContainer.viewContext
do
{
let homeCount = try moc.count(for: request)
if homeCount == 0
{
}
}catch{fatalError("Error in counting home records")}
}
Deleting data
let taskToDelete = tasks[indexPath.row]
context.delete(taskToDelete)
(UIApplication.shared.delegate as! AppDelegate).saveContext()
//fetch data again and reload table
do
{
try tasks = context.fetch(Task.fetchRequest())
}catch{}
Search and filter through records
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
do
{
let filteredreq : NSFetchRequest<Task> = Task.fetchRequest()
//this means that the attribute nameOfTask contains something
filteredreq.predicate = NSPredicate(format: "nameOfTask contains[c] %@", searchText)
//the array task of type Task will be populated
tasks = try context.fetch(filteredreq)
}catch{print(error.localizedDescription)}
}
Predicate: filter for exact search:
filteredreq.predicate = NSPredicate(format: "nameOfTask == %@", searchText)
if using predicate on a number:
request.predicate = NSPredicate(format: "aClassID == %@", cid as NSNumber)
if using predicate on a number:
request.predicate = NSPredicate(format: "aClassID == %@", cid as NSNumber)
More than one filter
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
do
{
let filteredreq : NSFetchRequest<Task> = Task.fetchRequest()
let namePredicate = NSPredicate(format: "nameOfTask contains[c] %@", searchText)
let imptPredicate = NSPredicate(format: "isImportant == %@", theSwitch.isOn as CVarArg)
let andPredicate = NSCompoundPredicate(type: .and, subpredicates: [namePredicate, imptPredicate])
filteredreq.predicate = andPredicate
tasks = try context.fetch(filteredreq)
}catch{print(error.localizedDescription)}
Update data
You have to apply a search,
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
do
{
var thisText = ""
if(previousText != nil)
{
thisText = previousText!
}
let filteredreq : NSFetchRequest<Task> = Task.fetchRequest()
//this means that the attribute nameOfTask contains something
filteredreq.predicate = NSPredicate(format: "nameOfTask == %@", thisText)
//the array task of type Task will be populated
tasks = try context.fetch(filteredreq)
if(tasks.count > 0)
{
let newTask = tasks[0]
//getting the values from the textfield and the switch
newTask.setValue(toUpdateTF.text, forKey: "nameOfTask")
newTask.setValue(toUpdateSW.isOn, forKey: "isImportant")
try context.save()
}
}catch{print(error.localizedDescription)}
Getting a unique key (like taskID) and increasing by 1
//put this in a separate method from the one where you have to add a new task
let appDelegate = UIApplication.shared.delegate as! AppDelegate
moc = appDelegate.persistentContainer.viewContext
var newTaskID: Int16
newTaskID = 1
let request: NSFetchRequest<Task> = Task.fetchRequest()
request.fetchLimit = 1
let sortDes = NSSortDescriptor(key: "taskID", ascending: false)
request.sortDescriptors = [sortDes]
do
{
let latestTask = try moc.fetch(request)
if latestTask.count > 0
{
let latestTaskTwo = latestTask.first
newTaskID = latestTaskTwo?.value(forKey: "taskID") as! Int16
newTaskID += 1
}
}catch{}
Getting today's date (with only day, month and year) and convert to NSDate to be stored in database
func getTodaysDate() -> NSDate
{
let dc = Calendar(identifier: .gregorian).dateComponents([.day, .month, .year], from: Date())
var dct = DateComponents()
dct.day = dc.day
dct.month = dc.month
dct.year = dc.year
let theNewDate = Calendar(identifier: .gregorian).date(from: dct)
let returnDate = theNewDate! as NSDate
return returnDate
}
Comments
Post a Comment