如何在Core Data/Table View中增删条目?Swift新手技术求助
Hey there! I see you're just getting started with Swift and Core Data, stuck on adding and deleting entries in your Table View for your bookstore app—let's fix that together, step by step. Since you already have an add button set up, we'll build right on that foundation.
NSFetchedResultsController This controller is your best friend for syncing Core Data changes directly to a Table View. It handles all the updates (add/delete/edit) automatically, so you don't have to manually reload the Table View every time something changes.
First, add a property for the controller in your ViewController.swift:
var fetchedResultsController: NSFetchedResultsController<Book>!
(Note: Make sure Book matches the name of your Core Data entity—if you named it something else, swap that out.)
Then set it up in viewDidLoad():
override func viewDidLoad() { super.viewDidLoad() // Link Table View delegate/data source to your View Controller tableView.delegate = self tableView.dataSource = self // Create a fetch request to get all Book entities let fetchRequest: NSFetchRequest<Book> = Book.fetchRequest() // Sort the books by title (you can change this to date added or author if you want) fetchRequest.sortDescriptors = [NSSortDescriptor(key: "title", ascending: true)] // Get the Core Data managed context from your app delegate guard let context = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer.viewContext else { print("Couldn't access Core Data context") return } // Initialize the fetched results controller fetchedResultsController = NSFetchedResultsController( fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, // No sections needed for now cacheName: nil ) // Set the delegate so the controller tells us when data changes fetchedResultsController.delegate = self // Perform the initial fetch to load existing books do { try fetchedResultsController.performFetch() } catch { print("Error fetching books: \(error.localizedDescription)") } }
Right now your button creates a title like "My Book (books.count)", but we need to actually save a new Book entity to Core Data. Update your add button's IBAction:
@IBAction func addBookTapped(_ sender: UIButton) { guard let context = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer.viewContext else { print("Couldn't access Core Data context") return } // Create a new Book entity instance let newBook = Book(context: context) // Generate the title using the current count of fetched books (plus 1 for the new one) let currentBookCount = fetchedResultsController.fetchedObjects?.count ?? 0 newBook.title = "My Book \(currentBookCount + 1)" // You can add more attributes here later (like author, genre, etc.) newBook.author = "Unknown Author" // Save the context to write the new book to Core Data do { try context.save() print("New book added!") } catch { print("Error saving book: \(error.localizedDescription)") } }
Replace any existing Table View data source methods with these, which use the fetched results controller to populate the Table View:
extension ViewController: UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // Return the number of books from the fetched results controller return fetchedResultsController.sections?[section].numberOfObjects ?? 0 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { // Dequeue a cell (make sure your cell identifier matches what's in Interface Builder!) let cell = tableView.dequeueReusableCell(withIdentifier: "BookCell", for: indexPath) // Get the book for this row let book = fetchedResultsController.object(at: indexPath) // Set the cell's text to the book title and author cell.textLabel?.text = book.title cell.detailTextLabel?.text = book.author return cell } }
First, enable swipe-to-delete by adding this data source method:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { if editingStyle == .delete { // Get the book to delete from the fetched results controller let bookToDelete = fetchedResultsController.object(at: indexPath) let context = fetchedResultsController.managedObjectContext // Delete the book from the context context.delete(bookToDelete) // Save the context to apply the delete do { try context.save() print("Book deleted!") } catch { print("Error deleting book: \(error.localizedDescription)") } } }
Then, add the NSFetchedResultsControllerDelegate methods to automatically update the Table View when Core Data changes:
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: // Add a new row when a book is inserted if let newIndexPath = newIndexPath { tableView.insertRows(at: [newIndexPath], with: .automatic) } case .delete: // Remove a row when a book is deleted if let indexPath = indexPath { tableView.deleteRows(at: [indexPath], with: .automatic) } case .update: // Reload a row when a book is updated if let indexPath = indexPath { tableView.reloadRows(at: [indexPath], with: .automatic) } case .move: // Handle row reordering if you add that later if let indexPath = indexPath, let newIndexPath = newIndexPath { tableView.deleteRows(at: [indexPath], with: .automatic) tableView.insertRows(at: [newIndexPath], with: .automatic) } @unknown default: break } } func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) { tableView.endUpdates() } }
- Make sure your Table View cell has the identifier "BookCell" set in Interface Builder (or update the identifier in
cellForRowAtto match your cell's ID). - Double-check that your Core Data
Bookentity has atitleattribute (andauthorif you used that code) of type String. - Ensure your View Controller conforms to
UITableViewDelegate,UITableViewDataSource, andNSFetchedResultsControllerDelegate(the extensions we added handle this, but make sure there are no typos).
That should do it! Now when you tap the add button, a new book will save to Core Data and show up in the Table View, and you can swipe left to delete any entry.
内容的提问来源于stack exchange,提问作者John Doe

