无法保存到核心数据中

时间:2018-06-15 04:23:46

标签: swift core-data

我有2个ViewControllers连接到Tab Bar Controller。一个ViewController应显示来自核心数据的表数据,另一个具有两个输入文本字段并输入按钮以将输入数据保存到核心数据。但是,我无法使用'var managedObjectContext:NSManagedObjectContext?'进行保存。我没有使用任何segues传递数据。我能正确编码吗?

import UIKit
import CoreData

class AddNameViewController: UIViewController {

// MARK: - Properties

@IBOutlet var firstNameTextField: UITextField!
@IBOutlet var lastNameTextField: UITextField!

var person: Person?
var managedObjectContext: NSManagedObjectContext?


override func viewDidLoad() {
    super.viewDidLoad()

    title = "Add Name"

}

// MARK: - Actions

@IBAction func save(_ sender: UIButton) {
    guard let managedObjectContext = managedObjectContext else { return }

    if person == nil {
        let newName = Person(context: managedObjectContext)

        newName.firstName = firstNameTextField.text
        newName.lastName = lastNameTextField.text
        newName.createdAt = Date().timeIntervalSince1970

    }
    try? managedObjectContext.save()
}

}

我可能会误导所有人。这是我的表视图代码。我在AppDelegate中没有样板文件。

import UIKit
import CoreData

class ViewController: UIViewController {

@IBOutlet var messageLabel: UILabel!
@IBOutlet var tableView: UITableView!
@IBOutlet var activityIndicatorView: UIActivityIndicatorView!

// MARK: - Persistent Container

private let persistentContainer = NSPersistentContainer(name: "People")

// MARK: - Fetch results controller

fileprivate lazy var fetchedResultsController:      NSFetchedResultsController<Person> = {
    let fetchRequest: NSFetchRequest<Person> = Person.fetchRequest()

    fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(Person.createdAt), ascending: true
        )]

    let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: self.persistentContainer.viewContext, sectionNameKeyPath: #keyPath(Person.lastName), cacheName: nil)

    fetchedResultsController.delegate = self

    return fetchedResultsController
}()

override func viewDidLoad() {
    super.viewDidLoad()

    title = "People"

    persistentContainer.loadPersistentStores { (persistentSoreDescription, error) in
        if let error = error {
            print("Unable to load persistent store")
            print("\(error), \(error.localizedDescription)")
        } else {
            self.setupView()

            do {
                try self.fetchedResultsController.performFetch()
            } catch {
                let fetchError = error as NSError
                print("Unable to perform fetch request")
                print("\(fetchError), \(fetchError.localizedDescription)")
            }

            self.updateView()
        }
    }

    NotificationCenter.default.addObserver(self, selector: #selector(applicationDidEnterBackground(_:)), name: Notification.Name.UIApplicationDidEnterBackground, object: nil)
}

// MARK: - Views

private func setupView() {
    setupMessageLabel()

    updateView()
}

fileprivate func updateView() {
    var hasNames = false

    if let people = fetchedResultsController.fetchedObjects {
        hasNames = people.count > 0
    }

    tableView.isHidden = !hasNames
    messageLabel.isHidden = hasNames

    activityIndicatorView.stopAnimating()
}

private func setupMessageLabel() {
    messageLabel.text = "You do not have names yet."
}

// MARK: - Notification handling

@objc func applicationDidEnterBackground(_ notification: Notification) {
    do {
        try persistentContainer.viewContext.save()
    } catch {
        print("Unable to save changes")
        print("\(error), \(error.localizedDescription)")
    }
}

}

extension ViewController: NSFetchedResultsControllerDelegate {

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
    tableView.beginUpdates()
}

func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
    tableView.endUpdates()

    updateView()
}

    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 .update:
        if let indexPath = indexPath, let cell = tableView.cellForRow(at: indexPath) as? PersonTableViewCell {
            configure(cell, at: indexPath)
        }
    default:
        break

    }
}

    func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange sectionInfo: NSFetchedResultsSectionInfo, atSectionIndex sectionIndex: Int, for type: NSFetchedResultsChangeType) {
    switch type {
    case .insert:
        tableView.insertSections(IndexSet(integer: sectionIndex), with: .fade)
    case .delete:
        tableView.deleteSections(IndexSet(integer: sectionIndex), with: .fade)
    default:
        break
    }
}

}

    extension ViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
    guard let sections = fetchedResultsController.sections  else { return 0 }
    return sections.count
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    guard let sectionInfo = fetchedResultsController.sections?[section] else { fatalError("Unexpected section") }
    return sectionInfo.numberOfObjects
}

func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    guard let sectionInfo = fetchedResultsController.sections?[section] else { fatalError("Unexpected section") }
    return sectionInfo.name
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    guard let cell = tableView.dequeueReusableCell(withIdentifier: PersonTableViewCell.reuseIdentifier, for: indexPath) as? PersonTableViewCell else {
        fatalError("Unexpected indexPath")
    }

    // Configure cell
    configure(cell, at: indexPath)

    return cell
}

func configure(_ cell: PersonTableViewCell, at indexPath: IndexPath) {
    let name = fetchedResultsController.object(at: indexPath)

    // Configure cell
    cell.firstNameLabel.text = name.firstName
    cell.lastNameLabel.text = name.lastName
}

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
    if editingStyle == .delete {
        let name = fetchedResultsController.object(at: indexPath)

        name.managedObjectContext?.delete(name)
    }
}

}

extension ViewController: UITabBarDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath, animated: true)
}

}

2 个答案:

答案 0 :(得分:0)

我认为你需要插入你想要保存的新记录,如下所示

//Create Reference for New AudioFile
let newPerson = NSEntityDescription.insertNewObject(forEntityName: "Person", into: context) as! Person

//Set Values
newPerson.fileName = firstNameTextField.text
newPerson.lastName = lastNameTextField.text
newPerson.craetedAt = Date().timeIntervalSince1970

//Save Context here
self.saveChanges() 


//MARK:- Saves all changes
func saveChanges()
{
  do{
       try context.save()
    }
    catch let error as NSError
    {
       // failure
       print(error)
    }
}

另外,我建议您检查与核心数据相关的工作代码

Github Link - https://github.com/RockinGarg/CoreData_Swift_Demo.git

此项目用于保存,获取,删除ID,使用单独的核心类(NSObject类)删除实体数据和谓词

答案 1 :(得分:0)

您的NSPersistentContainer参考在哪里?您必须首先使用上述容器初始化CoreData堆栈,然后尝试保存上下文。

尝试以下方法:

  1. 声明您的NSPersistentContainer参考。

    var container: NSPersistentContainer? = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer
    
  2. 使用容器的backgroundtask队列来保存上下文。

    container?.performBackgroundTask{ _ in
        guard let managedObjectContext = managedObjectContext else { return }
    
        if person == nil {
            let newName = Person(context: managedObjectContext)
    
            newName.firstName = firstNameTextField.text
            ...
    
        }
    
        try? managedObjectContext.save() 
    }
    
  3. 详细了解docs

    1. 我假设样板的persistentContainer代码是AppDelegate中你已经使用CoreData的东西,即。

      lazy var persistentContainer: NSPersistentContainer = {
      
          let container = NSPersistentContainer(name: "myModel")
          container.loadPersistentStores(completionHandler: { (storeDescription, error) in
              if let error = error as NSError? {
                  fatalError("Unresolved error \(error), \(error.userInfo)")
              }
          })
          return container
      }()