You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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.

1. First, Connect Core Data to Your Table View with 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)")
    }
}
2. Fix Your Add Book Button Action

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)")
    }
}
3. Implement Table View Data Source Methods

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
    }
}
4. Add Delete Functionality

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()
    }
}
Quick Checks Before Testing
  • Make sure your Table View cell has the identifier "BookCell" set in Interface Builder (or update the identifier in cellForRowAt to match your cell's ID).
  • Double-check that your Core Data Book entity has a title attribute (and author if you used that code) of type String.
  • Ensure your View Controller conforms to UITableViewDelegate, UITableViewDataSource, and NSFetchedResultsControllerDelegate (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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 08:32:34