【发布时间】:2025-12-21 13:10:11
【问题描述】:
我是 ios 应用程序开发的新手。我尝试制作一个包含 tableView 的简单应用程序,我们可以向 tableView 添加行,它可以使用 CoreData 将该数据保存在数据库中。我正在使用 NSFetchedResultController 来实现这一点,但是当我尝试在模拟器中运行它时,我添加到数据库中的数据无法获取。我尝试了其他各种解决方案,但无法解决。
CoreDataStack.swift
import Foundation
import CoreData
class CoreDataStack {
private init() {}
static let shared = CoreDataStack()
lazy var context = CoreDataStack.shared.persistentContainer.viewContext
var fetchedResultsController: NSFetchedResultsController<UserEntity> {
let fetchRequest: NSFetchRequest<UserEntity> = UserEntity.fetchRequest()
let nameSortDescriptor = NSSortDescriptor(key: "name", ascending: true)
let passwordSortDescriptor = NSSortDescriptor(key: "password", ascending: true)
fetchRequest.sortDescriptors = [nameSortDescriptor,passwordSortDescriptor]
let fetchResultsController = NSFetchedResultsController<UserEntity>(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
return fetchResultsController
}
lazy var persistentContainer: NSPersistentContainer = {
let container = NSPersistentContainer(name: "NSFRCCoreData")
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 () {
if context.hasChanges {
do {
try context.save()
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}
和我的视图控制器
import UIKit
import CoreData
class ViewController: UIViewController {
let fetchResultController = CoreDataStack.shared.fetchedResultsController
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
print(NSTemporaryDirectory())
title = "List"
tableView.dataSource = self
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
CoreDataStack.shared.fetchedResultsController.delegate = self
try! CoreDataStack.shared.fetchedResultsController.performFetch()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func addItems(_ sender: UIBarButtonItem) {
let alert = UIAlertController(title: "Enter The Item Name", message: nil, preferredStyle: .alert)
alert.addTextField(configurationHandler: nil)
alert .addTextField { (passwordTextField) in
let placeholder = NSAttributedString(string: "Password", attributes: nil)
passwordTextField.attributedPlaceholder = placeholder
}
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
let save = UIAlertAction(title: "Save", style:.default) { [unowned self] (action) in
guard let nameTextfield = alert.textFields?.first, let name = nameTextfield.text else {
return
}
guard let passwordTextfield = alert.textFields?[1], let password = passwordTextfield.text else {
return
}
let entity = NSEntityDescription.entity(forEntityName: "UserEntity", in: CoreDataStack.shared.context)
let userEntity = UserEntity(entity: entity!, insertInto: CoreDataStack.shared.context)
userEntity.name = name
userEntity.password = password
try? CoreDataStack.shared.context.save()
self.tableView.reloadData()
}
alert.addAction(cancel)
alert.addAction(save)
self.present(alert, animated: true, completion: nil)
}
}
extension ViewController: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
guard let sectionCount = CoreDataStack.shared.fetchedResultsController.sections?.count else {
return 0
}
return sectionCount
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard let sections = CoreDataStack.shared.fetchedResultsController.sections else {
return 0
}
return sections[section].numberOfObjects
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DataCell", for: indexPath)
let userEntity = CoreDataStack.shared.fetchedResultsController.object(at: indexPath)
cell.textLabel?.text = userEntity.name
cell.detailTextLabel?.text = userEntity.password
return cell
}
}
extension ViewController: NSFetchedResultsControllerDelegate {
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.beginUpdates()
}
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)
}
case .delete:
if let indexPath = indexPath {
tableView.deleteRows(at: [indexPath], with: .fade)
}
case .move:
if let indexPath = indexPath, let newIndexPath = newIndexPath {
tableView.moveRow(at: indexPath, to: newIndexPath)
}
case .update:
if let indexPath = indexPath, let cell = tableView.cellForRow(at: indexPath){
cell.textLabel?.text = "Hello"
}
}
}
func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
tableView.endUpdates()
}
}
TableView 不显示任何数据,但是当我使用 sqlite 浏览器检查时,它包含保存数据。
【问题讨论】:
-
您的
fetchedResultsController是一个计算属性,每次计算时都会返回一个不同的 FRC 实例。因此,performFetch在 tableView 数据源方法中与 FRC 不同的实例上执行。 -
@pdasdf 感谢它现在运行良好
-
@pbasdf 如果你有答案,你真的应该把它作为答案而不是评论。这样做会使问题看起来仍然没有答案。
-
@TomHarrington 你是对的,对不起。我现在将添加一个答案。