kyle-c
11/19/2017 - 12:05 PM

Core Data

Getting Started with Core Data

  1. Project creation

Don't forget to check "Use Core Data" checkbox

  1. Model definition

  • Open .xcdatamodeld file
  • Create entities model
  • Create properties
  • Create relationship ("toXXX" for the name)
  • Set relationship for all and then add reverse for all
  • Set relationship attributes (in "Attributes inspector" on the right)
  1. Create NSManagedObject subclass

  • Select all entities (V.I.P)
  • Click on "Editor" -> "Create NSManagedObject subclass"
  • Put all files created ending with "properties.swift" in "Model" -> "Generated"
  • Grab others and put it in "Model" in case of problems, see troubelshots section
  1. [OPTIONAL] Set NSManagedObject properties

Like following

@objc(Item)
public class Item: NSManagedObject {
  
  public override func awakeFromInsert() {
    super.awakeFromInsert()
    
    self.creationDate = NSDate()
  }
}
  1. Create variables and add methods in app delegate

// MARK: - Core Data stack

  lazy var persistentContainer: NSPersistentContainer = {
      let container = NSPersistentContainer(name: "WishList")
      container.loadPersistentStores(completionHandler: { (storeDescription, error) in
          if let error = error as NSError? {
              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 {
              let nserror = error as NSError
              fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
          }
      }
  }

}

let ad = UIApplication.shared.delegate as! AppDelegate
let context = ad.persistentContainer.viewContext
  1. [OPTIONAL] Display data (Tableview in our exemple)

// MARK: - NSFetchedResultsControllerDelegate
extension MainVC: NSFetchedResultsControllerDelegate {
  func attempFetch(){
    let fetchRequest: NSFetchRequest<Item> = Item.fetchRequest()
    let dateSort = NSSortDescriptor(key: "creationDate", ascending: false)
    let priceSort = NSSortDescriptor(key: "price", ascending: false)
    let titleSort = NSSortDescriptor(key: "title", ascending: false)
    
    if segmentedControl.selectedSegmentIndex == 0 {
      fetchRequest.sortDescriptors = [dateSort]
    } else if segmentedControl.selectedSegmentIndex == 1 {
      fetchRequest.sortDescriptors = [priceSort]
    } else {
      fetchRequest.sortDescriptors = [titleSort]
    }
    
    
    
    let controller = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
    
    controller.delegate = self
    self.controller = controller
    
    do {
      try controller.performFetch()
    } catch {
      let error = error as NSError
      print("\(error)")
    }
  }
  
  func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
    tableView.beginUpdates()
  }
  
  func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
    tableView.endUpdates()
  }
  
  func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
    switch type {
    case .insert:
      if let indexPath = newIndexPath {
        tableView.insertRows(at: [indexPath], with: .fade)
      }
      break
    case .delete:
      if let indexPath = indexPath {
        tableView.deleteRows(at: [indexPath], with: .fade)
      }
      break
    case .move:
      if let indexPath = indexPath {
        tableView.deleteRows(at: [indexPath], with: .fade)
      }
      if let indexPath = newIndexPath {
        tableView.insertRows(at: [indexPath], with: .fade)
      }
      break
    case .update:
      if let indexPath = indexPath {
        let cell = tableView.cellForRow(at: indexPath) as! ItemCell
        configureCell(cell: cell, indexPath: indexPath)
      }
      break
    }
  }
}
  1. Create an object

let item = Item(context: context)
// set item properties
ad.saveContext()
  1. Update an object

let item = itemToEdit // get NSObject instance
// set item properties
ad.saveContext()
  1. Delete an object

context.delete(itemToDelete!)
ad.saveContext()

Troubelshooting

  • first select the files generated (those ending in ~CoreDataClass and ~CoreDataProperties) and delete them ---> move them to trash
  • Go to Menu/Product/(alt key)+Clean Build Folder
  • Select the .xcdatamodeld and save (Command + S)
  • Quit the project and reopen it.
  • Make sure that the "Utilities" right bar of Xcode is visible and the "Show the Data Model Inspector" is selected.
  • Select the .xcdatamodeld and select all the ENTITIES.
  • On the Data Model Inspector find the section "Class" and change the attribute "Codegen" TO "Manual/None"
  • Save the model (I don't know if actually this makes a difference but won't hurt). (Command + S)
  • Go to Menu/Editor/Create NSManagedObjectSubclass
  • Select all, next...

Tags : CoreData / coredata / Core data / Core Data / core data / core Data