应用因while循环卡顿崩溃,求UITableViewCell置空/释放方案
Hey there, let's break down your issues and fix them one by one—your code has a few key problems causing the crash, and we'll also address the cell management confusion:
First: Stop using cellForRow(at:) to get cells for data saving
This is the root of your crash and卡顿 issue. cellForRow(at:) only returns cells that are currently visible on the screen. When your counter exceeds the number of visible rows in section 1, this method returns nil, and your forced unwrap (as! TableViewCell) causes an immediate crash.
Plus, you should never read data from cells to save to CoreData. Cells are just display components—you should always maintain a dedicated data source array (e.g., var shoppingItems: [ShoppingItemModel] = []) that holds all the user's input. When the user edits a cell, update the data source; when saving, iterate over the data source instead of cells.
Fix the dequeueReusableCell return nil issue
If dequeueReusableCell(withIdentifier:for:) is returning nil, you're missing a critical step: registering your cell. Do one of these:
- In Storyboard: Select your
TableViewCell, go to the Identity Inspector, and set the "Reuse Identifier" to exactly"listdetails". - Programmatically: Add this to your
viewDidLoad():tableView.register(TableViewCell.self, forCellReuseIdentifier: "listdetails")
Once registered, you can safely use dequeue in your cellForRowAt: method:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "listdetails", for: indexPath) as! TableViewCell // Populate cell from your data source array let item = shoppingItems[indexPath.row] cell.listItem.text = item.name cell.qtytextfield.text = String(item.qty) cell.unitstextfield.text = item.units return cell }
Fix the while loop crash & logic errors
Looking at your loop:
- You're creating a duplicate
ShoppingDetailsinstance inside theif storeFlag == trueblock (you already created one outside). - You're messing up Core Data relationship handling with
mutableCopy()andlist.removeAllObjects()—this is unnecessary and breaks data saving. - You're relying on cells to get input data, which fails when cells are off-screen.
Here's the revised saveButton method using a data source array:
// First, define a simple model to hold your items (or use Core Data objects directly) struct ShoppingItemModel { var name: String var qty: String var units: String } // Declare this as a property in your view controller var shoppingItems: [ShoppingItemModel] = [] @IBAction func saveButton(_ sender: UIBarButtonItem) { // Get store name cell safely guard let storeCell = tableView.cellForRow(at: IndexPath(row:0, section: 0)) as? TableViewCell, let storeName = storeCell.storeName.text?.trimmingCharacters(in: .whitespaces), !storeName.isEmpty else { // Show alert to user: store name is required return } let storeFlag = validateShoppingList(storeName: storeName) guard storeFlag else { // Show validation failure alert return } // Get location name safely let locationCell = tableView.cellForRow(at: IndexPath(row:1, section: 0)) as? TableViewCell let locationName = locationCell?.locationName.text?.trimmingCharacters(in: .whitespaces) ?? "" // Create Core Data objects let shoppingDetails = ShoppingDetails(context: managedContext) shoppingDetails.storeName = storeName shoppingDetails.location = locationName shoppingDetails.initialLetter = storeName.first?.description let seqNo = ShoppingDetails.getSeqNo(managedObjectContext: managedContext) + 1 shoppingDetails.seqNo = Int32(seqNo) // Save each item from the data source array for item in shoppingItems { let listDetails = ListDetails(context: managedContext) listDetails.listItem = item.name.trimmingCharacters(in: .whitespaces) listDetails.qty = Int64(item.qty) ?? 0 listDetails.units = item.units listDetails.isChecked = false // Use Core Data's auto-generated relationship method shoppingDetails.addToShoppingToList(listDetails) } // Save context safely do { try coreData.saveContext() // Navigate to the next screen guard let vc = storyboard?.instantiateViewController(withIdentifier: "StoreDisplayController") as? StoreDisplayController else { return } vc.managedContext = managedContext vc.coreData = coreData vc.storeName = storeName navigationController?.pushViewController(vc, animated: true) } catch { print("Save failed: \(error.localizedDescription)") managedContext.rollback() // Show error alert to user } }
Do you need to manually release/empty UITableViewCell?
No! UITableView has a built-in cell reuse pool that automatically manages cell memory. When cells scroll off-screen, the system moves them to the reuse pool instead of deallocating them. When you need a new cell, dequeueReusableCell fetches one from the pool.
You don't need to manually release or empty cells—just make sure you're properly reconfiguring cells in cellForRowAt: every time they're reused.
内容的提问来源于stack exchange,提问作者BoR

