Swift iOS下UITableView租金类型筛选崩溃问题求助
Fixing "Index Out of Range" Crash & Rental Type Filtering Issues
Let’s break down what’s causing your crash and fix the filtering logic step by step:
1. Root Causes of the Problem
Your crash and filtering issues stem from two key mistakes:
- Misaligned row selection: When displaying filtered results, your
didSelectRowAtmethod still uses the fullrentalsArrayinstead of the filtered subset. Since the filtered array’s indices don’t match the full array, this triggers an out-of-bounds error. - Broken filtering logic: You’re adding items to
filteredArrarytwice (once for price matches, once for type matches), creating duplicates and ignoring cases where both filters should apply together.
2. Step-by-Step Fixes
Fix 1: Rewrite the Filtering Logic
Replace your Firebase observer’s filtering code with a combined condition that checks all active filters at once:
// Inside your Firebase observer closure self.rentalsArray = [] self.filteredArrary = [] // Note: rename to filteredArray for Swift naming consistency if let snapshots = snapshot.children.allObjects as? [DataSnapshot] { for snap in snapshots { if let dicOfRentals = snap.value as? Dictionary<String,AnyObject> { let key = snap.key let rental = Rental(postID: key, userData: dicOfRentals) self.rentalsArray.append(rental) // Check if rental matches ALL active filters var shouldInclude = true // Validate price filter (if set) if let maxPrice = self.filterByPrice { guard let priceStr = rental.price, let priceAsFloat = Float(priceStr) else { shouldInclude = false continue } shouldInclude = maxPrice >= priceAsFloat } // Validate rental type filter (if set) if let allowedTypes = self.filteredRentalTypes, !allowedTypes.isEmpty { guard let rentalType = rental.rentalType else { shouldInclude = false continue } shouldInclude = allowedTypes.contains(rentalType) } // Add to filtered array only if it passes all checks if shouldInclude { self.filteredArrary.append(rental) } } } self.tableView.reloadData() }
Fix 2: Fix Row Selection Logic
Update didSelectRowAt to use the correct array (filtered or full) based on whether filtered results exist:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let selectedRental: Rental if !filteredArrary.isEmpty { selectedRental = filteredArrary[indexPath.row] } else { selectedRental = rentalsArray[indexPath.row] } selectedRental.incrimentViews() // Note: rename to incrementViews() for correct spelling guard let postID = selectedRental.postID else { return } let postViewsToFB = DataService.ds.DBrefRentals.child(postID) postViewsToFB.child("views").setValue(selectedRental.views) // Pass the selected rental directly to the segue performSegue(withIdentifier: "toDetailVC" , sender: selectedRental) }
Fix 3: Simplify prepareForSegue & Remove Force Unwraps
Use the sender to pass the selected rental, eliminating risky force-unwraps of index paths:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "toDetailVC" { guard let destination = segue.destination as? DetailVC, let selectedRental = sender as? Rental else { return } // Safely assign values without force-unwrapping destination.emailAdress = selectedRental.email destination.bond = selectedRental.bond destination.dateAval = selectedRental.dateAval destination.pets = selectedRental.pets destination.rent = selectedRental.price destination.rentalTitle = selectedRental.title destination.imageURL = selectedRental.imageURL destination.des = selectedRental.description destination.rentalType = selectedRental.rentalType destination.streetName = selectedRental.streetName destination.city = selectedRental.city destination.postcode = selectedRental.postcode } }
Fix 4: Clean Up Cell Configuration (Optional but Recommended)
Add safe optional handling to your cell setup:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let rental: Rental if !filteredArrary.isEmpty { rental = filteredArrary[indexPath.row] } else { rental = rentalsArray[indexPath.row] } guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as? RentalCell else { return RentalCell() } // Handle image caching safely if let imageURL = rental.imageURL, !imageURL.isEmpty { if let cachedImage = RentalTableViewVC.imageCache.object(forKey: imageURL as NSString) { cell.configureCell(rental: rental, image: cachedImage) } else { cell.configureCell(rental: rental, image: nil) // Add async image loading here if you want to fetch missing images } } else { cell.configureCell(rental: rental, image: nil) } return cell }
3. Additional Recommendations
- Fix typos: Rename
filteredArrarytofilteredArrayandincrimentViewstoincrementViewsto follow Swift naming conventions. - Refresh filters on return: Add code to re-run the filtering logic in
viewWillAppearso changes from your Eureka filter VC take effect immediately. - Minimize force unwraps: Use
guard let/if leteverywhere to make your code more crash-resistant.
内容的提问来源于stack exchange,提问作者George Woolley
相关产品推荐
相关产品推荐

