Reputation: 1027
I am a beginner trying to learn the basic concepts of iOS and swift. So, I am making a demo app wherein I store names of people using UITableView. For making the app storage persistent I used core data with only one entity named 'Person' with a single attribute as 'name' which is a string value. To level up this application I need to add delete functionality. As we see in lot of iOS apps, the delete feature on swiping left, I want to implement the same functionality in this app. I have looked up on various solutions but I can't really get a hold of how I'll be able to delete a row and update the table in core data at the same time. I have been stuck at this problem since hours trying to delete a row in UITableView using swipe gesture. Any help would be appreciated.
Below is my code:
ViewController.swift
import UIKit
import CoreData
class ViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
var people: [NSManagedObject] = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
title = "The List"
tableView.register(UITableViewCell.self,
forCellReuseIdentifier: "Cell")
}
// Implement the addName IBAction
@IBAction func addName(_ sender: UIBarButtonItem) {
let alert = UIAlertController(title: "New Name", message: "Add a new name", 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: .cancel)
alert.addTextField()
alert.addAction(saveAction)
alert.addAction(cancelAction)
present(alert, animated: true)
}
// MARK: - SAVING TO CORE DATA
// CoreData kicks in here!
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: "Person", in: managedContext)!
let person = NSManagedObject(entity: entity, insertInto: managedContext)
// 3
person.setValue(name, forKeyPath: "name")
// 4
do {
try managedContext.save()
people.append(person)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
// MARK: - FETCHING FROM CORE DATA
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// 1
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
// 2
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: "Person")
// 3
do {
people = try
managedContext.fetch(fetchRequest)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
}
// MARK: - UITableViewDataSource
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return people.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let person = people[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = person.value(forKeyPath: "name") as? String
return cell
}
}
// MARK: - UITableViewDelegate
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == .delete) {
// handle delete (by removing the data from your array and updating the tableview)
}
}
}
App Screen:
Data model:
Upvotes: 0
Views: 73
Reputation: 794
You have to delete the managed object by calling delete(_:) on the managed object context, e.g.:
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
let person = people[indexPath.row]
managedContext.delete(person)
And to commit the change, call save() on the managed object context:
try? managedContext.save()
Then, don't forget to also update the person cache in your view controller:
people.remove(at: indexPath.row)
And finally, delete the row in your table view:
tableView.deleteRows(at: [indexPath], with: .automatic)
This should accomplish what you want.
The missing implementation could therefor be:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// delete the person in core data
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
let person = people[indexPath.row]
managedContext.delete(person)
try? managedContext.save()
// remove the person from cache
people.remove(at: indexPath.row)
// delete row from table view
tableView.deleteRows(at: [indexPath], with: .automatic)
}
}
Upvotes: 1