我有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)
}
}
答案 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堆栈,然后尝试保存上下文。
尝试以下方法:
声明您的NSPersistentContainer参考。
var container: NSPersistentContainer? = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer
使用容器的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()
}
详细了解docs。
我假设样板的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
}()