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

应用因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:

  1. You're creating a duplicate ShoppingDetails instance inside the if storeFlag == true block (you already created one outside).
  2. You're messing up Core Data relationship handling with mutableCopy() and list.removeAllObjects()—this is unnecessary and breaks data saving.
  3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:44:01