Swift搜索栏筛选后详情页跳转错误问题求助
Hey there, let's break down why this is happening and fix it right away!
What's Causing the Bug?
From what you've described, the root issue is almost certainly that you're using the indexPath.row from your filtered table view to access your original, unfiltered arrays (names, namesDesc, etc.).
Here's the scenario:
- When no filter is applied, your table uses the full
namesarray, soindexPath.row = 0maps to the first item innames,row=1maps to the second, and so on—this works fine. - When you filter down to just the second item, your table now only shows one row (index 0), but you're still using that index 0 to pull data from the original
namesarray. That's why it jumps to the first item's detail page instead of the filtered one!
The Fix: Use a Filtered Data Source Array
The solution is to maintain a separate array that holds only the filtered results, and use this array for all table view operations (cell setup, row count, and selection).
Let's walk through the steps with code:
Add Filtered Data Arrays
First, declare variables to store your filtered results, matching your original data structure:import UIKit // Original full data var names = [String]() var namesDesc = [String]() var namesDescW = [String]() // Assuming this is another related array // Filtered data (we'll update this when searching) var filteredNames = [String]() var filteredNamesDesc = [String]() var filteredNamesDescW = [String]() var isSearching = false // Track if we're in search/filter modeUpdate Your Filter Logic
When the user types in the search bar, update the filtered arrays to match the search criteria, then reload the table:func updateFilter(with searchText: String) { isSearching = !searchText.isEmpty if isSearching { // Filter all arrays together to keep indexes aligned let filteredPairs = zip(names, zip(namesDesc, namesDescW)) .filter { $0.0.lowercased().contains(searchText.lowercased()) } // Unpack the filtered pairs back into separate arrays filteredNames = filteredPairs.map { $0.0 } filteredNamesDesc = filteredPairs.map { $0.1.0 } filteredNamesDescW = filteredPairs.map { $0.1.1 } } else { // Reset to full data when search is cleared filteredNames = names filteredNamesDesc = namesDesc filteredNamesDescW = namesDescW } tableView.reloadData() }Use the Correct Array in Table View Data Source Methods
Make sure your table uses either the filtered or original array based onisSearching:func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return isSearching ? filteredNames.count : names.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "YourCellID", for: indexPath) // Get the correct data based on search state let currentName = isSearching ? filteredNames[indexPath.row] : names[indexPath.row] let currentDesc = isSearching ? filteredNamesDesc[indexPath.row] : namesDesc[indexPath.row] cell.textLabel?.text = currentName cell.detailTextLabel?.text = currentDesc // Set other properties from namesDescW similarly return cell }Fix the Selection Logic
Finally, in the row selection method, use the filtered array to get the correct data for the detail page:func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) // Grab the correct item based on search state let selectedName = isSearching ? filteredNames[indexPath.row] : names[indexPath.row] let selectedDesc = isSearching ? filteredNamesDesc[indexPath.row] : namesDesc[indexPath.row] let selectedDescW = isSearching ? filteredNamesDescW[indexPath.row] : namesDescW[indexPath.row] // Pass this data to your detail view controller let detailVC = DetailViewController() detailVC.name = selectedName detailVC.desc = selectedDesc detailVC.descW = selectedDescW navigationController?.pushViewController(detailVC, animated: true) }
Pro Tip: Use a Data Model (Avoid Parallel Arrays!)
To make this even cleaner and avoid index mismatches entirely, wrap your data into a single model struct:
struct Item { let name: String let desc: String let descW: String } // Now you only need two arrays instead of three+ var allItems = [Item]() var filteredItems = [Item]()
This way, filtering becomes simpler, and you never have to worry about keeping multiple arrays in sync:
func updateFilter(with searchText: String) { isSearching = !searchText.isEmpty filteredItems = allItems.filter { $0.name.lowercased().contains(searchText.lowercased()) } tableView.reloadData() }
Final Check
After implementing this, when you filter and tap the result, the indexPath.row will map to the correct item in the filteredItems (or filtered arrays), so your detail page will load the right content every time.
内容的提问来源于stack exchange,提问作者Kubik Sukenik

