如何修改TableView中不同选中行的值?求通用实现代码
Hey there! Let's tackle this TableView row selection and value update problem together. I’ll break down a robust, general-purpose solution that addresses the core issue you mentioned—specifically that problematic self.weekdayPrice = [Int(price)!] line.
First, Let's Diagnose Your Original Problem
That line is replacing your entire data array with a single-element array containing the new price. No wonder it's not working as expected! Instead of updating only the selected rows, you're overwriting all rows with the same value. We need to modify only the entries corresponding to selected rows, not the whole dataset.
Step-by-Step General Solution
1. Use a Data Model to Track Selection State
First, define a simple model to hold both the value and whether the row is selected. This makes it easy to track which rows need updating:
struct PriceItem { var value: Int var isSelected: Bool // Tracks if the row is selected for update }
Replace your original weekdayPrice array with this model array:
var priceItems: [PriceItem] = []
2. Configure TableView for Multi-Selection
Enable multi-selection and update cell appearance based on selection state:
override func viewDidLoad() { super.viewDidLoad() tableView.allowsMultipleSelection = true // Load your initial data into priceItems here } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "YourCellID", for: indexPath) let item = priceItems[indexPath.row] cell.textLabel?.text = "\(item.value)" // Show checkmark for selected rows cell.accessoryType = item.isSelected ? .checkmark : .none return cell }
3. Update Selection State When Rows Are Tapped
Sync the model's isSelected property with user taps:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { priceItems[indexPath.row].isSelected = true tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark } override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) { priceItems[indexPath.row].isSelected = false tableView.cellForRow(at: indexPath)?.accessoryType = .none }
4. Implement Custom Value Update for Selected Rows
Add a trigger (like a button) to let users input the custom value, then update only selected rows:
@IBAction func updateSelectedRowsTapped(_ sender: UIButton) { // Show alert to get custom value from user let alert = UIAlertController(title: "Enter New Value", message: "Input the value to set for selected rows", preferredStyle: .alert) alert.addTextField { textField in textField.keyboardType = .numberPad } let confirmAction = UIAlertAction(title: "Update", style: .default) { [weak self] _ in guard let self = self, let inputText = alert.textFields?.first?.text, let newPrice = Int(inputText) else { return } // Iterate through data and update only selected items for index in self.priceItems.indices { if self.priceItems[index].isSelected { self.priceItems[index].value = newPrice // Refresh the specific row to show the new value self.tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .automatic) } } // Optional: Clear selection after update self.tableView.clearSelection() self.priceItems.indices.forEach { self.priceItems[$0].isSelected = false } } alert.addAction(confirmAction) alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) present(alert, animated: true) }
Full Working Example
Here’s a complete, self-contained view controller to test this logic:
import UIKit class PriceTableVC: UITableViewController { var priceItems: [PriceItem] = [ PriceItem(value: 15, isSelected: false), PriceItem(value: 25, isSelected: false), PriceItem(value: 35, isSelected: false), PriceItem(value: 45, isSelected: false) ] struct PriceItem { var value: Int var isSelected: Bool } override func viewDidLoad() { super.viewDidLoad() tableView.allowsMultipleSelection = true tableView.register(UITableViewCell.self, forCellReuseIdentifier: "PriceCell") navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Update Selected", style: .plain, target: self, action: #selector(updateSelectedRows)) } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { priceItems.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "PriceCell", for: indexPath) let item = priceItems[indexPath.row] cell.textLabel?.text = "Price: $\(item.value)" cell.accessoryType = item.isSelected ? .checkmark : .none return cell } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { priceItems[indexPath.row].isSelected = true cellForRow(at: indexPath)?.accessoryType = .checkmark } override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) { priceItems[indexPath.row].isSelected = false cellForRow(at: indexPath)?.accessoryType = .none } @objc func updateSelectedRows() { let alert = UIAlertController(title: "Set New Price", message: "Enter the new value", preferredStyle: .alert) alert.addTextField { $0.keyboardType = .numberPad } let confirmAction = UIAlertAction(title: "Apply", style: .default) { [weak self] _ in guard let self = self, let input = alert.textFields?.first?.text, let newPrice = Int(input) else { return } for (index, item) in self.priceItems.enumerated() { if item.isSelected { self.priceItems[index].value = newPrice self.tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .fade) } } self.tableView.clearSelection() self.priceItems.indices.forEach { self.priceItems[$0].isSelected = false } } alert.addAction(confirmAction) alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) present(alert, animated: true) } }
This approach keeps your data intact for unselected rows, lets users input custom values, and only updates the rows they’ve chosen. No more overwriting your entire dataset!
内容的提问来源于stack exchange,提问作者Dima

