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

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 didSelectRowAt method still uses the full rentalsArray instead 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 filteredArrary twice (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
    }
}

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 filteredArrary to filteredArray and incrimentViews to incrementViews to follow Swift naming conventions.
  • Refresh filters on return: Add code to re-run the filtering logic in viewWillAppear so changes from your Eureka filter VC take effect immediately.
  • Minimize force unwraps: Use guard let/if let everywhere to make your code more crash-resistant.

内容的提问来源于stack exchange,提问作者George Woolley

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:45:28