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

Swift 4中基于Yelp自动补全API实现TableView搜索过滤

Hey there! Let's break down how to get your Yelp autocomplete results showing up under the search bar and properly filter your TableView. I'll walk you through step-by-step fixes and improvements:


First: Refactor Your Data Sources (Critical!)

Right now, you're using separate arrays (nameArray, locationArray, etc.) which makes filtering and maintenance messy. Let's switch to storing full business objects instead:

// Store all original businesses loaded on startup
var originalBusinesses: [CDYelpBusiness] = []
// Filtered businesses for your main TableView
var filteredBusinesses: [CDYelpBusiness] = []
// Autocomplete suggestions to show under the search bar
var autocompleteSuggestions: [String] = []

When you first load your Yelp data, populate originalBusinesses with the full CDYelpBusiness objects—this lets you easily access names, addresses, images, and other properties later.


Step 1: Add an Autocomplete Dropdown TableView

The UISearchBar doesn't have a built-in dropdown, so we'll add a small UITableView to display suggestions right below it. Add this to your ViewController:

let autocompleteTableView = UITableView()

override func viewDidLoad() {
    super.viewDidLoad()
    
    // Configure the autocomplete table
    autocompleteTableView.frame = CGRect(
        x: searchBar.frame.origin.x,
        y: searchBar.frame.origin.y + searchBar.frame.height,
        width: searchBar.frame.width,
        height: 200 // Adjust height as needed
    )
    autocompleteTableView.delegate = self
    autocompleteTableView.dataSource = self
    autocompleteTableView.register(UITableViewCell.self, forCellReuseIdentifier: "AutocompleteCell")
    autocompleteTableView.isHidden = true // Hide until we have suggestions
    view.addSubview(autocompleteTableView)
    
    // Don't forget to enable the search bar's cancel button
    searchBar.showsCancelButton = true
}

Step 2: Fix the searchBar(textDidChange) Method

Update your API call to populate the autocomplete list and handle state properly. We'll also add a small delay to avoid spamming the Yelp API as the user types:

var autocompleteTimer: Timer?

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    // Cancel any pending API requests
    autocompleteTimer?.invalidate()
    autocompleteSuggestions.removeAll()
    
    // Hide the dropdown if the search bar is empty
    guard !searchText.isEmpty else {
        autocompleteTableView.isHidden = true
        return
    }
    
    // Wait 0.3 seconds after the user stops typing to make the API call
    autocompleteTimer = Timer.scheduledTimer(withTimeInterval: 0.3, repeats: false) { [weak self] _ in
        self?.fetchAutocompleteResults(for: searchText)
    }
}

private func fetchAutocompleteResults(for searchText: String) {
    yelpAPIClient.autocompleteBusinesses(
        byText: searchText,
        latitude: Double(Location.sharedInstance.latitude),
        longitude: Double(Location.sharedInstance.longitude),
        locale: CDYelpLocale.english_unitedStates
    ) { [weak self] response in
        guard let self = self, let response = response, let businesses = response.businesses else {
            self?.autocompleteTableView.isHidden = true
            return
        }
        
        // Populate autocomplete suggestions with business names
        self.autocompleteSuggestions = businesses.compactMap { $0.name }
        // Show the dropdown and refresh its data
        self.autocompleteTableView.isHidden = false
        self.autocompleteTableView.reloadData()
        
        // Optional: Pre-filter your main TableView with the autocomplete results
        self.filteredBusinesses = businesses
        self.yelpTableView.reloadData()
    }
}

The [weak self] avoids memory leaks—always use this in async closures!


Step 3: Implement Autocomplete TableView Logic

Update your existing TableView delegate/dataSource methods to handle both the autocomplete dropdown and your main business list:

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if tableView == autocompleteTableView {
        return autocompleteSuggestions.count
    } else {
        // Show filtered results if we're searching, else show all businesses
        return isFiltering() ? filteredBusinesses.count : originalBusinesses.count
    }
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if tableView == autocompleteTableView {
        let cell = tableView.dequeueReusableCell(withIdentifier: "AutocompleteCell", for: indexPath)
        cell.textLabel?.text = autocompleteSuggestions[indexPath.row]
        return cell
    } else {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: "YelpCell") as? YelpCell else {
            return UITableViewCell()
        }
        // Get the correct business based on filtering state
        let business = isFiltering() ? filteredBusinesses[indexPath.row] : originalBusinesses[indexPath.row]
        
        // Populate cell using the full business object
        cell.YelpNameLbl.text = business.name
        cell.yelpAddressLbl.text = business.location?.address1
        if let imageURL = business.imageURL {
            cell.yelpImg.downloadedFrom(url: imageURL)
        }
        cell.yelpDollarSignLbl.text = business.price
        if let distance = business.distance {
            // Convert meters to miles (divide by 1609.34) or keep as meters
            cell.distanceFromYou.text = String(format: "%.2f mi", distance / 1609.34)
        }
        return cell
    }
}

// Handle taps on autocomplete suggestions
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if tableView == autocompleteTableView {
        let selectedName = autocompleteSuggestions[indexPath.row]
        // Fill the search bar with the selected suggestion
        searchBar.text = selectedName
        // Hide the dropdown
        autocompleteTableView.isHidden = true
        // Filter main TableView to show only the selected business
        filteredBusinesses = originalBusinesses.filter { $0.name == selectedName }
        yelpTableView.reloadData()
        // Hide the keyboard
        searchBar.resignFirstResponder()
    }
}

Step 4: Polish Filtering Logic

Update your isFiltering() and helper methods to work with the new data sources:

func searchBarIsEmpty() -> Bool {
    return searchBar.text?.isEmpty ?? true
}

func isFiltering() -> Bool {
    return !searchBarIsEmpty() && !filteredBusinesses.isEmpty
}

// Handle cancel button tap
func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
    searchBar.text = ""
    autocompleteTableView.isHidden = true
    filteredBusinesses.removeAll()
    yelpTableView.reloadData()
    searchBar.resignFirstResponder()
}

Quick Notes for Improvement

  • Use AutoLayout: Instead of hardcoding the autocomplete table's frame, use AutoLayout constraints to make it adapt to different screen sizes.
  • Error Handling: Add error cases for the Yelp API call (e.g., network failures) to inform the user.
  • Scope Buttons: If you plan to use the scope buttons, update selectedScopeButtonIndexDidChange to filter originalBusinesses by category or price range.

内容的提问来源于stack exchange,提问作者Coding while Loading

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:14:25