I am still struggling with CoreData to start the week haha. I finally succeeded in saving and fetching my array, now is time to edit and delete.
I'm adding the delete function first but I'm having trouble passing in the correct argument:
Core Data functions:
class CDHandler: NSObject {
private class func getContext() -> NSManagedObjectContext {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
}
class func saveObject(name:String, code:String, symbol:String, placeholder:String, amount:String) -> Bool {
let context = getContext()
let entity = NSEntityDescription.entity(forEntityName: "CryptosMO", in: context)
let managedObject = NSManagedObject(entity: entity!, insertInto: context)
managedObject.setValue(name, forKey: "name")
managedObject.setValue(code, forKey: "code")
managedObject.setValue(symbol, forKey: "symbol")
managedObject.setValue(placeholder, forKey: "placeholder")
managedObject.setValue(amount, forKey: "amount")
do {
try context.save()
return true
} catch {
return false
}
}
class func fetchObject() -> [CryptosMO]? {
let context = getContext()
var cryptos: [CryptosMO]? = nil
do {
cryptos = try context.fetch(CryptosMO.fetchRequest()) as? [CryptosMO]
return cryptos
} catch {
return cryptos
}
}
class func deleteObject(crypto: CryptosMO) -> Bool {
let context = getContext()
context.delete(crypto)
do {
try context.save()
return true
} catch {
return false
}
}
}
Creating and saving the array :
if addedCrypto != "" {
if addedCrypto == "Bitcoin BTC" {
if CDHandler.saveObject(name: "Bitcoin", code: "bitcoin", symbol: "BTC", placeholder: "BTC Amount", amount: "0.0") {
for crypto in CDHandler.fetchObject()! {
print("\(String(describing: crypto.name))'s symbol is \(String(describing: crypto.symbol))")
}
}
}
}
Fetching Core Data for the TableView:
override func viewWillAppear(_ animated: Bool) {
tableView.delegate = self
tableView.dataSource = self
if CDHandler.fetchObject() != nil {
cryptos = CDHandler.fetchObject()!
tableView.reloadData()
}
}
TableView functions:
extension WalletTableViewController: UITableViewDelegate, UITableViewDataSource, CryptoCellDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cryptos.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! WalletTableViewCell
cell.cryptoNameLabel.text = cryptos[indexPath.row].name
cell.amountTextField.placeholder = cryptos[indexPath.row].placeholder
cell.delegate = self
cell.amountTextField.delegate = self
return cell
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
cryptos.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
CDHandler.deleteObject(crypto: cryptos) // <----- Cannot convert value of type '[CryptosMO]' to expected argument type 'CryptosMO'
}
}
}
What is the problem here? I can change func deleteObject(crypto: CryptosMO) to func deleteObject(crypto: [CryptosMO]) but then I get Cannot convert value of type '[CryptosMO]' to expected argument type 'NSManagedObject'.
I read that delete() only take an NSManagedObject as its sole argument so I believe I created an incorrect object in the first place to be able to delete it??
Just call this method and pass entity with managedObjectwhich you want to delete:
func deleteData(entity:String,deleteObject:NSManagedObject){
//for iOS 10+
// let delegate = UIApplication.shared.delegate as? AppDelegate
// let context = delegate!.persistentContainer.viewContext
let context = getContext()
context.delete(deleteObject)
do {
try context.save()
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let selectedManagedObject = cryptos[indexPath.row]
deleteData(entity:"yourEntityName",deleteObject: selectedManagedObject)
cryptos.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
same like save method you can edit, just you need to pass the managedObject which you want to edit:
class func updateObject(name:String, code:String, symbol:String, placeholder:String, amount:String,selectedManagedObject:NSManagedObject) {
let context = getContext()
selectedManagedObject.setValue(name, forKey: "name")
selectedManagedObject.setValue(code, forKey: "code")
selectedManagedObject.setValue(symbol, forKey: "symbol")
selectedManagedObject.setValue(placeholder, forKey: "placeholder")
selectedManagedObject.setValue(amount, forKey: "amount")
do {
try context.save()
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
When you call CDHandler.deleteObject(crypto: ...) just pass (crypto: cryptos[indexPath.row]) instead of (crypto: cryptos).
...
CDHandler.deleteObject(crypto: cryptos[indexPath.row])
cryptos.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
Related
I'm actually doing an app for recipe, I already did the persistent data to save my ingredients in the list but when I want to delete my ingredients with my button it works at the first time but come back when I restart my app.
Here's my code :
class AddIngredientController: UIViewController, ShowAlert {
#IBOutlet weak var textField: UITextField!
#IBOutlet weak var ingredientsTableView: UITableView!
var itemArrayIngredient = [Item]()
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
override func viewDidLoad() {
super.viewDidLoad()
let dataFilePath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
print(dataFilePath)
loadItems()
}
func saveItems() {
do {
try context.save()
} catch {
print("Error saving context \(error)")
}
}
func loadItems(with request: NSFetchRequest<Item> = Item.fetchRequest()) {
do {
itemArrayIngredient = try context.fetch(request)
} catch {
print("Error fetching data from context \(error)")
}
}
#IBAction func clearButton(_ sender: UIButton) {
context.delete() //Here the problem
itemArrayIngredient.removeAll()
saveItems()
ingredientsTableView.reloadData()
}
#IBAction func addButton(_ sender: UIButton) {
if textField.text!.isEmpty {
showAlert(title: "No Ingredients", message: "Please, add some ingredients to your list.")
} else {
newIngredientAdded()
}
}
func newIngredientAdded() {
let newItem = Item(context: context)
newItem.title = textField.text!
itemArrayIngredient.append(newItem)
saveItems()
ingredientsTableView.reloadData()
textField.text! = ""
}
}
extension AddIngredientController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return itemArrayIngredient.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customSearchCell", for: indexPath)
let item = itemArrayIngredient[indexPath.row]
cell.textLabel?.text = item.title
cell.textLabel?.textColor = UIColor.white
cell.textLabel?.font = UIFont(name: "Marker Felt", size: 19)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
saveItems()
tableView.deselectRow(at: indexPath, animated: true)
}
}
context.delete must be called with an argument. For example
#IBAction func clearButton(_ sender: UIButton) {
itemArrayIngredient.forEach { context.delete($0) }
itemArrayIngredient.removeAll()
saveItems()
ingredientsTableView.reloadData()
}
You need to delete a specific object from core data. Please refer below code
let fetchRequest = NSFetchRequest(entityName: "EntityName")
if let result = try? context.fetch(fetchRequest) {
for object in result {
//Please check before delete operation
if object.id == Your_Deleted_Object_ID{
context.delete(object)
}
}
}
You can delete all data from particular entity by using NSBatchDeleteRequest. See following code. The main advantage of NSBatchDeleteRequest is, you don't need to enumerate on array of object.
let fetch = NSFetchRequest<NSFetchRequestResult>(entityName: "EntityName")
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetch)
do {
try context.execute(deleteRequest)
} catch {
print(error.localizedDescription)
}
I added a homework page using the user default.
Null value also adding to tableView and delete function not working.
ButtonAction
#IBAction func addHomeWork(_ sender: Any) {
let newHomeWork = HomeWork(addtitle:addHomeworktxt.text!)
HomeWork.saveHomeWork(homeWork: newHomeWork)
}
viewWillAppear
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
if let arrayDetails = HomeWork.getHomeWork() {
homeWorkArray = arrayDetails
}
}
EditingStyle
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCell.EditingStyle.delete {
homeWorkArray.remove(at: indexPath.row)
self.tableView.deleteRows(at: [indexPath], with: UITableView.RowAnimation.automatic)
self.tableView.reloadData()
HomeWork.getHomeWork()
}
}
model class HomeWork
class HomeWork: Codable {
var title:String
init(addtitle:String) {
self.title = addtitle}
public static func getHomeWork() -> [HomeWork]? {
var homeWorkArray:[HomeWork] = []
if let homeWorkData = UserDefaults.standard.data(forKey: "homeworkData"){
homeWorkArray = try! JSONDecoder().decode([HomeWork].self, from: homeWorkData)
}
return homeWorkArray
}
saveHomeWork method in HomeWork model class
public static func saveHomeWork(homeWork:HomeWork){
var retrivedHomeWorkArray:[HomeWork] = []
if let homeWorkData = UserDefaults.standard.data(forKey: "homeworkData"){
retrivedHomeWorkArray = try! JSONDecoder().decode([HomeWork].self, from: homeWorkData)
}
if retrivedHomeWorkArray.count == 0 {
var homeWorkArray = [HomeWork]()
homeWorkArray.append(homeWork)
let homeWorkDat = try! JSONEncoder().encode(homeWorkArray)
UserDefaults.standard.set(homeWorkDat, forKey: "homeworkData")
}else{
retrivedHomeWorkArray.append(homeWork)
let homeWorkDat = try! JSONEncoder().encode(retrivedHomeWorkArray)
UserDefaults.standard.set(homeWorkDat, forKey: "homeworkData") } }}
When you delete , you don't alter saved array
homeWorkArray.remove(at: indexPath.row)
self.tableView.deleteRows(at: [indexPath], with: UITableView.RowAnimation.automatic)
self.tableView.reloadData()
HomeWork.getHomeWork()
so consider adding a function that re-saves the current array like
public static func reSave(homeWorks:[HomeWork]){
let homeWorkDat = try! JSONEncoder().encode(homeWorks)
UserDefaults.standard.set(homeWorkDat, forKey: "homeworkData")
}
then replace above code with
homeWorkArray.remove(at: indexPath.row)
self.tableView.deleteRows(at: [indexPath], with: UITableView.RowAnimation.automatic)
HomeWork.reSave(homeWorks:homeWorkArray)
I am creating an ios app that will show me a user specific set of tasks everyday that i click to delete to show its done. I save the tasks in core data, and just delete the tableview row on click. I dont delete the data in coredata as its userdefined and need to reload it everyday. I use a newDay() function to decide to load data from coredata if the app is opened on a new day. What should i do to remember which all tasks have been done for the day? Do i need to create another enitity to remember which all tasks are completed or is there an simpler way?
var tasks: [NSManagedObject] = []
let defaults = UserDefaults.standard
var calender = Calendar.current
override func viewDidLoad() {
super.viewDidLoad()
title = "DailyTasker"
navigationItem.leftBarButtonItem = editButtonItem
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let checkDate = newDay()
if checkDate{
//1
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext =
appDelegate.persistentContainer.viewContext
//2
let fetchRequest =
NSFetchRequest<NSManagedObject>(entityName: "Task")
//3
do {
tasks = try managedContext.fetch(fetchRequest)
defaults.set(Date(), forKey: "LastRun")
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
}
}
func newDay() -> Bool{
if let lastRun = defaults.object(forKey: "LastRun") as? Date{
if !calender.isDateInToday(lastRun){
return true
} else {
return false
}
} else {
return true
}
}
#IBAction func addName(_ sender: UIBarButtonItem) {
let alert = UIAlertController(title: "New Task",
message: "Add a new task",
preferredStyle: .alert)
let saveAction = UIAlertAction(title: "Save",
style: .default) {
[unowned self] action in
guard let textField = alert.textFields?.first,
let nameToSave = textField.text else {
return
}
self.save(name: nameToSave)
self.tableView.reloadData()
}
let cancelAction = UIAlertAction(title: "Cancel",
style: .default)
alert.addTextField()
alert.addAction(saveAction)
alert.addAction(cancelAction)
present(alert, animated: true)
}
func save(name: String) {
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
// 1
let managedContext =
appDelegate.persistentContainer.viewContext
// 2
let entity =
NSEntityDescription.entity(forEntityName: "Task",
in: managedContext)!
let task = NSManagedObject(entity: entity,
insertInto: managedContext)
// 3
task.setValue(name, forKeyPath: "name")
// 4
do {
try managedContext.save()
tasks.append(task)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return tasks.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let task = tasks[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "TaskerCell", for: indexPath)
cell.textLabel?.text = task.value(forKeyPath: "name") as? String
return cell
}
// Override to support editing the table view.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// Delete the row from the data source
tasks.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tasks.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
You could add a date attribute to your task and name it lastDonefor instance. Then you set that to current date time when a task is done and also use a predicate when fetching task instances so you only get those not done today.
task.lastDone = Date()
I am not sure how you define "today" but this question should help you create a predicate that properly filters your task although you might also want to include tasks where lastDone is null.
I am not sure Why you can't delete the data. Is it due to specifications.
If not then, when you save your task in coredata simply assign it with a unique Identifer(id) and then you can create your own data stack Method to delete the specific task.
You can create a data Model Class or struct for the task example
class TaskData {
var id: Int!
var task: String!
init(id: Int, task: String) {
self.id = id
self.task = task
}
}
Save task as this dataClass into coreData.
When you delete the row at that time captue the Task Id and delete it from coreDataStack.
A good way will be to create a TaskManager Singelton class to handle all the core data Methods.
I'm creating a contacts app, so far I've successfully managed to save items to my tableview. I have a search bar and I want to filter out my cells by first name, I know since I'm working in Core Data I'll have to use fetchResultsController and NSPredicate. I'm having trouble figuring this stuff all out, maybe someone can help me out?
Also here is my Core Data entity, just in case.
Entity: Contact
Attributes:
firstName ,String
lastName, String
dateOfBirth, String
phoneNumber, String
zipCode, String
I know some of the code may be incomplete, but I just need direction on where to take this. I just want the user to type a name and it will filter the cells by first name. Let me know if there is more information you need.
Now here is the code in my ContactsTableVC:
import UIKit
import CoreData
class ContactsTableVC: UITableViewController, UISearchBarDelegate, NSFetchedResultsControllerDelegate {
#IBOutlet weak var searchBar: UISearchBar!
var isFiltered: Bool = false
//Holds the core data model
var persons: [Person] = []
override func viewDidLoad() {
super.viewDidLoad()
searchBar.delegate = self
self.tableView.separatorStyle = UITableViewCellSeparatorStyle.none
self.tableView.backgroundColor = UIColor(red: 240/255.0, green: 240/255.0, blue: 240/255.0, alpha: 1.0)
fetch()
self.tableView.reloadData()
}
func getContext () -> NSManagedObjectContext {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
}
// MARK: - Searchbar
//add fetchrequest to did ebgin editing
func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {
}
func searchBarTextDidEndEditing(_ searchBar: UISearchBar) {
if(searchBar.text == "") {
isFiltered = false
} else {
isFiltered = true
}
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
filter(text: searchText)
}
// MARK: - Fetchresults controller / filtering data
func filter(text: String) {
//Create fetch request
let fetchRequest = NSFetchRequest<Person>()
// guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return } replaced with getcontext
// let managedObjectContext = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Contact", in: getContext())
fetchRequest.entity = entity
let sortDescriptor = NSSortDescriptor(key: "firstName", ascending: false)
let sortDescriptors: [Any] = [sortDescriptor]
fetchRequest.sortDescriptors = sortDescriptors as? [NSSortDescriptor] ?? [NSSortDescriptor]()
if(text.characters.count > 0) {
let predicate = NSPredicate(format: "(firstName CONTAINS[c] %#)", text)
fetchRequest.predicate = predicate
}
let loadedEntities: [Person]? = try? getContext().fetch(fetchRequest)
filteredContacts = [Any](arrayLiteral: loadedEntities) as! [Person]
self.tableView.reloadData()
}
// MARK: - Data Source
func fetch() {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedObjectContext = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName:"Contact")
do {
persons = try managedObjectContext.fetch(fetchRequest) as! [Person] //NSManagedObject
} catch let error as NSError {
print("Could not fetch. \(error)")
}
}
func save(firstName: String, lastName: String, dob: String, phoneNumber: String, zipCode: String) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedObjectContext = appDelegate.persistentContainer.viewContext
guard let entity = NSEntityDescription.entity(forEntityName:"Contact", in: managedObjectContext) else { return }
let person = NSManagedObject(entity: entity, insertInto: managedObjectContext)
person.setValue(firstName, forKey: "firstName")
person.setValue(lastName, forKey: "lastName")
person.setValue(dob, forKey: "dateOfBirth")
person.setValue(phoneNumber, forKey: "phoneNumber")
person.setValue(zipCode, forKey: "zipCode")
do {
try managedObjectContext.save()
self.persons.append(person as! Person) //previously just contact, no casting!
} catch let error as NSError {
print("Couldn't save. \(error)")
}
}
func update(indexPath: IndexPath, firstName: String, lastName: String, dob: String, phoneNumber: String, zipCode: String) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedObjectContext = appDelegate.persistentContainer.viewContext
let contact = persons[indexPath.row]
contact.setValue(firstName, forKey: "firstName")
contact.setValue(lastName, forKey: "lastName")
contact.setValue(dob, forKey: "dateOfBirth")
contact.setValue(phoneNumber, forKey: "phoneNumber")
contact.setValue(zipCode, forKey: "zipCode")
do {
try managedObjectContext.save()
persons[indexPath.row] = contact
} catch let error as NSError {
print("Couldn't update. \(error)")
}
}
func delete(_ contact: NSManagedObject, at indexPath: IndexPath) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
let managedObjectContext = appDelegate.persistentContainer.viewContext
managedObjectContext.delete(contact)
persons.remove(at: indexPath.row)
//Always remember to save after deleting, updates Core Data
do {
try managedObjectContext.save()
} catch {
print("Something went wrong \(error.localizedDescription)")
}
}
// MARK: - Table View Setup
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return persons.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ContactCell", for: indexPath) as? PersonsCell
let person = persons[indexPath.row]
cell?.firstName?.text = person.value(forKey:"firstName") as? String
cell?.lastName?.text = person.value(forKey:"lastName") as? String
cell?.dob?.text = person.value(forKey:"dateOfBirth") as? String
cell?.phoneNumber?.text = person.value(forKey:"phoneNumber") as? String
cell?.zipCode?.text = person.value(forKey:"zipCode") as? String
return cell!
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 75
}
// Override to support conditional editing of the table view.
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
// MARK: - Navigation
#IBAction func unwindToContactsList(segue:UIStoryboardSegue) {
if let viewController = segue.source as? AddContactVC {
guard let _firstName: String = viewController.firstNameLbl.text,
let _lastName: String = viewController.lastNameLbl.text,
let _dob: String = viewController.dateOfBirthLbl.text,
let _phoneNumber: String = viewController.phoneNumberLbl.text,
let _zipCode: String = viewController.zipCodeLbl.text
else { return }
if _firstName != "" && _lastName != "" && _dob != "" && _phoneNumber != "" && _zipCode != "" {
if let indexPath = viewController.indexPathForContact {
update(indexPath: indexPath, firstName: _firstName, lastName: _lastName, dob: _dob, phoneNumber: _phoneNumber, zipCode: _zipCode)
print("Any updates?")
} else {
save(firstName: _firstName, lastName: _lastName, dob: _dob, phoneNumber: _phoneNumber, zipCode: _zipCode)
print("added to tableview") //this runs twice for some reason...
}
}
tableView.reloadData()
} else if let viewController = segue.source as? EditContactVC {
if viewController.isDeleted {
guard let indexPath: IndexPath = viewController.indexPath else { return }
let person = persons[indexPath.row]
delete(person, at: indexPath)
tableView.reloadData()
}
}
}
}
Here is a sample code to achieve your goal with NSFetchedResultsController. I omitted some irrelevant codes.
class ContactViewController: UITableViewController {
let fetchedResultsController: NSFetchedResultsController<Contact>!
func searchTextFieldDidEditingChanged(_ textField: UITextField) {
let text = textField.text ?? ""
refetch(with: text)
}
// The key is you need change the predicate when searchTextField's
// value changed, and invoke proformFetch() again
func refetch(with text: String) {
let predicate = NSPredicate(format: "firstName CONTAINS %#", text)
fetchedResultsController.fetchRequest.predicate = predicate
do {
try self.fetchedResultsController.performFetch()
tableView.reloadData()
} catch let error as NSError {
loggingPrint("Error: \(error.localizedDescription)")
}
}
}
// MARK: - Table datasource
extension ContactViewController {
override func numberOfSections(in tableView: UITableView) -> Int {
return fetchedResultsController.sections!.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
let sectionInfo = fetchedResultsController.sections![section]
return sectionInfo.numberOfObjects
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ContactCell", for: indexPath) as? PersonsCell
let contact = fetchedResultsController.object(at: indexPath)
cell.contact = contact
return cell!
}
}
You can use the sortDescriptors property of NSPredicate to filter the results of your fetch request.
Check the link for more info:
How to sort a fetch in Core Data
I am making a Notes app using with Xcode in Swift 3. I have a way to add notes, a way to save, delete, and title notes. When I make notes, they are listed from oldest to newest like so:
https://i.stack.imgur.com/1K59R.png
Here is my code:
//
// ListNotesTableViewController.swift
// NotesApp
//
// Created by on 6/22/17.
// Copyright © 2016. All rights reserved.
//
import UIKit
class ListNotesTableViewController: UITableViewController {
var notes = [Note](){
didSet {
tableView.reloadData()
}
}
override func viewDidLoad() {
super.viewDidLoad()
notes = CoreDataHelper.retrieveNotes()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return notes.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "listNotesTableViewCell", for: indexPath) as! ListNotesTableViewCell
let row = indexPath.row
let note = notes[row]
cell.noteTitleLabel.text = note.title
cell.noteModificationTimeLabel.text = note.modificationTime?.convertToString()
return cell
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
CoreDataHelper.delete(note: notes[indexPath.row])
notes = CoreDataHelper.retrieveNotes()
}
}
#IBAction func unwindToListNotesViewController(_ segue: UIStoryboardSegue){
self.notes = CoreDataHelper.retrieveNotes()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let identifier = segue.identifier {
if identifier == "displayNote" {
print("Table view cell tapped")
let indexPath = tableView.indexPathForSelectedRow!
let note = notes[indexPath.row]
let displayNoteViewController = segue.destination as! DisplayNoteViewController
displayNoteViewController.note = note
} else if identifier == "addNote" {
print("+ button tapped")
}
}
}
}
The problem is located (I think, but I'm not sure) near the bottom. I wish I could be more specific on where the problem is, but then I would be able to solve this problem myself. This is my 3rd day with this language and I am very confused.
Anyways, how can I change the ordering of order in which the notes are displayed from Newest/Last Modified to Oldest/First Modified?
Edit: Here is the code for the CoreDataHelper:
//
// CoreDataHelper.swift
// NotesApp
//
// Created by on 6/22/17.
// Copyright © 2017. All rights reserved.
//
import Foundation
import CoreData
import UIKit
class CoreDataHelper {
static let appDelegate = UIApplication.shared.delegate as! AppDelegate
static let persistentContainer = appDelegate.persistentContainer
static let managedContext = persistentContainer.viewContext
static func newNote() -> Note {
let note = NSEntityDescription.insertNewObject(forEntityName: "Note", into: managedContext) as! Note
return note
}
static func saveNote() {
do {
try managedContext.save()
} catch let error as NSError {
print("Could not save \(error)")
}
}
static func delete(note: Note) {
managedContext.delete(note)
saveNote()
}
static func retrieveNotes() -> [Note] {
let fetchRequest = NSFetchRequest<Note>(entityName: "Note")
do {
let results = try managedContext.fetch(fetchRequest)
return results
} catch let error as NSError {
print("Could not fetch \(error)")
}
return []
}
}
The problem as others have mentioned is not the table. You have to provide your data in order and since you're getting it from coredata it's fairly easy
static func retrieveNotes() -> [Note] {
let fetchRequest = NSFetchRequest<Note>(entityName: "Note")
fetchRequest.sortDescriptors = [NSSortDescriptor(key:"date", ascending: true)] //date would be whatever theKeyWhereYouStoreTheDateInYourDatabaseIs
do {
let results = try managedContext.fetch(fetchRequest)
return results
} catch let error as NSError {
print("Could not fetch \(error)")
}
return []
}