[swift] CoreDataを使用してタスクを追加・削除

CoreDataを使用してタスクを追加・削除するには以下のコード

Closureを使用して、保存や削除が完全に終了してからデータの再読込及びReload Tableを実行している

xcode ProjectをCoreDataなしで作成してしまったので、途中からCoreDataを追加している。

目次

CoreDataの作成

Data Modelファイルの作成

スクリーンショット 2017-10-10 9.51.45

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」を追加

スクリーンショット 2017-10-10 9.53.26

 

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



コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です