#ios #swift #uitableview #core-data
#iOS #swift #uitableview #core-данные
Вопрос:
Я создал простой ToDoList с простым CoreData. Добавлено создание строки, удаление строки, но невозможно изменить строку. Я не могу понять, как это сделать.
Я добавил AlertController, чтобы изменить его.
Мои CoreData состоят из одного свойства: name . И я создаю интерфейс без раскадровки, просто код. Как обновить объект CoreData?
import UIKit
import CoreData
class ViewController: UITableViewController {
private let cellID = "cell"
private var tasks = [Task]()
private let appDelegate = UIApplication.shared.delegate as! AppDelegate //
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
title = "To do list"
navigationController?.navigationBar.barTintColor = UIColor(displayP3Red: 21/255,
green: 101/255,
blue: 192/255,
alpha: 1)
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Add",
style: .plain,
target: self,
action: #selector(addNewTask))
navigationController?.navigationBar.tintColor = .white
tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellID)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let managedContext = appDelegate.persistentContainer.viewContext
let fetchRequest: NSFetchRequest<Task> = Task.fetchRequest()
do {
tasks = try managedContext.fetch(fetchRequest)
} catch let error {
print("Failed to fetch data", error)
}
}
// MARK: Table View Data Source
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tasks.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellID, for: indexPath)
let task = tasks[indexPath.row]
cell.textLabel?.text = task.name
return cell
}
override func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let editNotesAction = UITableViewRowAction(style: .default, title: "Edit") { (action: UITableViewRowAction, indexPath: IndexPath) in
let alert = UIAlertController(title: "Edit", message: "", preferredStyle: .alert)
let saveAction = UIAlertAction(title: "Save", style: .default, handler: { (action) in
})
let cancelAction = UIAlertAction(title: "Cancel", style: .default)
alert.addTextField()
alert.addAction(saveAction)
alert.addAction(cancelAction)
self.present(alert, animated: true)
}
editNotesAction.backgroundColor = .blue
let deleteNotesAction = UITableViewRowAction(style: .default, title: "Delete") { (action: UITableViewRowAction, indexPath: IndexPath) in
let managedContext = self.appDelegate.persistentContainer.viewContext
managedContext.delete(self.tasks[indexPath.row])
self.tasks.remove(at: indexPath.row)
do {
try managedContext.save()
} catch let error {
print(error.localizedDescription)
}
self.tableView.deleteRows(at: [indexPath], with: .fade)
}
return [deleteNotesAction, editNotesAction]
}
@objc private func addNewTask() {
let alert = UIAlertController(title: "New Task", message: "", preferredStyle: .alert)
let saveAction = UIAlertAction(title: "Save", style: .default) { _ in
guard let task = alert.textFields?.first?.text, task.isEmpty == false else { return }
self.saveData(task)
self.tableView.reloadData()
}
let cancelAction = UIAlertAction(title: "Cancel", style: .destructive)
alert.addTextField()
alert.addAction(saveAction)
alert.addAction(cancelAction)
present(alert, animated: true)
}
private func saveData(_ taskName: String) {
let managedContext = appDelegate.persistentContainer.viewContext
guard let entity = NSEntityDescription.entity(forEntityName: "Task", in: managedContext) else { return }
let task = NSManagedObject(entity: entity, insertInto: managedContext) as! Task
task.name = taskName
do {
try managedContext.save()
tasks.append(task)
} catch let error {
print("Failed to save task", error.localizedDescription)
}
}
}
Ответ №1:
Ваше действие сохранения должно извлечь значение из текстового поля и присвоить его правильному управляемому объекту.
let saveAction = UIAlertAction(title: "Save", style: .default, handler: { (action) in
guard let textField = alert.textFields.first else { return }
let task = tasks[indexPath.row]
task.name = textField.text
})
Если name
это необязательно, вам нужно будет использовать nil-coalescing для указания значения по умолчанию для имени, если текстовое поле пустое. ( task.name = textField.text ?? "SomeDefaultName"
)