[swift] CoreDataを使用してタスクを追加・削除
CoreDataを使用してタスクを追加・削除するには以下のコード
Closureを使用して、保存や削除が完全に終了してからデータの再読込及びReload Tableを実行している
xcode ProjectをCoreDataなしで作成してしまったので、途中からCoreDataを追加している。
目次
CoreDataの作成
Data Modelファイルの作成
New File で新規ファイルを作成(CoreData -> Data Model)
Data Modelのファイル名は「HitList」としているため、Project内に「HitList.xcdatamodeld」というファイルが追加される
エンティティとAttributeを追加
今回はPersonというEntity(SQLで言うDBテーブル)を作成し、その中のAttribute(SQLで言うカラム)にNameを追加している。
Add Entityで「Person」という名前で追加
Add Attirbuteで「Name」を追加
AppDelegate.swift
AppDelegate.swiftに以下のコードを追加
*CoreDataを最初からProjectに追加した時は、自動でコードが追加されている。
NSPersistentContainerには先程作成したData Modelのファイル名を記述しておく
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentContainer(name: "HitList")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
// MARK: - Core Data Saving support
func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
ViewController.swift
ViewControllerにTableViewを実装
fetchPersonDataでCoreDataからNSManagedObjectを読み込んで配列peopleに要素として追加している。
NSManagedObjectはDictionary型なので下記のようにAttribute名でそれぞれの要素を取得することができる。
cell.textLabel?.text = person.value(forKeyPath: “name”) as? String
import UIKit import CoreData class ViewController: UIViewController { @IBOutlet weak var tableView: UITableView! var people: [NSManagedObject] = [] override func viewDidLoad() { super.viewDidLoad() title = "The List" tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell") } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) fetchPersonData(){ self.tableView.reloadData() } } @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.saveName(name: nameToSave){ self.fetchPersonData() { 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 } let managedContext = appDelegate.persistentContainer.viewContext let entity = NSEntityDescription.entity(forEntityName: "Person", in: managedContext)! let person = NSManagedObject(entity: entity, insertInto: managedContext) person.setValue(name, forKeyPath: "name") do { try managedContext.save() people.append(person) } 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 } func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) { if editingStyle == .delete { let person = people[indexPath.row] deleteName(managedObject: person){ self.fetchPersonData(){ self.tableView.deleteRows(at: [indexPath], with: .fade) self.tableView.reloadData() } } } } } //MARK: Controll CoreData extension ViewController { func saveName(name: String, completion: (()->Void)?) { guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return } let managedContext = appDelegate.persistentContainer.viewContext let entity = NSEntityDescription.entity(forEntityName: "Person", in: managedContext)! let person = NSManagedObject(entity: entity, insertInto: managedContext) person.setValue(name, forKeyPath: "name") do { try managedContext.save() completion?() } catch let error as NSError { print("Could not save. \(error), \(error.userInfo)") } } func fetchPersonData(completion: (()->Void)?) { guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return } let managedContext = appDelegate.persistentContainer.viewContext let fetchRequest = NSFetchRequest(entityName: "Person") do { people = try managedContext.fetch(fetchRequest) completion?() } catch let error as NSError { print("Could not fetch. \(error), \(error.userInfo)") } } func updateName(managedObject: NSManagedObject, newName: String, completion: (()->Void)?) { guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return } let managedContext = appDelegate.persistentContainer.viewContext do { managedObject.setValue(newName, forKey: "name") try managedContext.save() completion?() } catch { } } func deleteName(managedObject: NSManagedObject, completion: (()->Void)?) { guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return } let managedContext = appDelegate.persistentContainer.viewContext do { managedContext.delete(managedObject) print("deleteName") try managedContext.save() completion?() } catch { print("deleteName error") } } }