[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")
}
}
}