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

Swift MVVM架构下TableView搜索结果点击跳转展示数据问题

How to Navigate from SearchingList to FoodList/MenuList with Corresponding Data in Swift MVVM

Got it, let's walk through how to make this navigation and data handoff work smoothly in your Swift MVVM setup. Here's a step-by-step approach tailored to your three-page structure:

1. Define a Unified Source Identifier for Search Results

First, you need a way to track where each search item comes from (foodlist or menulist) and carry its corresponding data. Create an enum to encapsulate this:

enum SearchItemSource {
    case food(FoodModel) // Replace with your actual FoodModel type
    case menu(MenuModel) // Replace with your actual MenuModel type
}

Update your SearchingListModel to include this source property—so every search result holds a reference to its original model and which list it belongs to.

2. Add a Selection Callback in SearchingListViewModel

In MVVM, ViewModels handle business logic, so we'll add a closure to notify the ViewController when an item is selected:

class SearchingListViewModel {
    // Your existing properties (like searchResults array)
    var searchResults: [SearchingListModel] = []
    
    // Closure to trigger navigation
    var onItemSelected: ((SearchItemSource) -> Void)?
    
    // Call this when a table cell is tapped
    func handleItemSelection(at indexPath: IndexPath) {
        let selectedItem = searchResults[indexPath.row]
        onItemSelected?(selectedItem.source)
    }
}

3. Bind the Callback and Handle Navigation in SearchingListViewController

In your SearchingListViewController, connect the ViewModel's closure to trigger navigation. Depending on the source, instantiate the correct ViewController and pass the data:

class SearchingListViewController: UIViewController {
    private let viewModel = SearchingListViewModel()
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        setupViewModelBindings()
        // Your existing table setup code
    }

    private func setupViewModelBindings() {
        viewModel.onItemSelected = { [weak self] source in
            guard let self = self else { return }
            
            switch source {
            case .food(let selectedFood):
                // Instantiate FoodListViewController (adjust for Storyboards or code-based)
                let foodVC = FoodListViewController()
                // Pass the selected food to its ViewModel
                foodVC.viewModel.selectedFood = selectedFood
                // Push to navigation stack (ensure this VC is in a UINavigationController)
                self.navigationController?.pushViewController(foodVC, animated: true)
                
            case .menu(let selectedMenu):
                // Repeat the same pattern for MenuList if needed
                let menuVC = MenuListViewController()
                menuVC.viewModel.selectedMenu = selectedMenu
                self.navigationController?.pushViewController(menuVC, animated: true)
            }
        }
    }

    // TableView didSelectRowAt delegate method
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        viewModel.handleItemSelection(at: indexPath)
        tableView.deselectRow(at: indexPath, animated: true)
    }
}

Note: If you're using Storyboards, replace the ViewController instantiation with storyboard?.instantiateViewController(withIdentifier: "YourStoryboardID") as! FoodListViewController.

4. Update FoodList to Display the Selected Data

Modify FoodListViewModel to receive the selected food and adjust the data source accordingly. You can either filter the list to show only the selected item, or scroll to its position in the full list:

Option A: Filter the List to Show Only the Selected Food

class FoodListViewModel {
    var allFoods: [FoodModel] = [] // Your full food dataset
    var filteredFoods: [FoodModel] = []
    var selectedFood: FoodModel? {
        didSet {
            if let food = selectedFood {
                filteredFoods = [food]
                // Notify ViewController to reload the table
                onDataUpdated?()
            }
        }
    }
    var onDataUpdated: (() -> Void)?
}

Option B: Scroll to the Selected Food in the Full List

class FoodListViewModel {
    var allFoods: [FoodModel] = []
    var selectedFood: FoodModel? {
        didSet {
            if let food = selectedFood, let index = allFoods.firstIndex(where: { $0.id == food.id }) {
                selectedIndex = index
                onSelectedIndexReady?()
            }
        }
    }
    var selectedIndex: Int?
    var onSelectedIndexReady: (() -> Void)?
}

Then update FoodListViewController to respond to these changes:

class FoodListViewController: UIViewController {
    let viewModel = FoodListViewModel()
    @IBOutlet weak var tableView: UITableView!

    override func viewDidLoad() {
        super.viewDidLoad()
        setupViewModelBindings()
    }

    private func setupViewModelBindings() {
        // For Option A: Reload table when filtered data changes
        viewModel.onDataUpdated = { [weak self] in
            self?.tableView.reloadData()
        }

        // For Option B: Scroll to the selected row
        viewModel.onSelectedIndexReady = { [weak self] in
            guard let self = self, let index = self.viewModel.selectedIndex else { return }
            let indexPath = IndexPath(row: index, section: 0)
            self.tableView.scrollToRow(at: indexPath, at: .middle, animated: true)
        }
    }

    // Update your TableView data source methods to use viewModel.filteredFoods (Option A) or viewModel.allFoods (Option B)
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return viewModel.filteredFoods.count // Or viewModel.allFoods.count for Option B
    }
}

Key Notes

  • Ensure all your ViewControllers are embedded in a UINavigationController so pushViewController works.
  • If you're using dependency injection (a common MVVM best practice), you can pass the ViewModel to the FoodListViewController instead of setting properties directly.
  • Make sure your model types (FoodModel, MenuModel) have a unique identifier (like an id property) to reliably find the correct item in the full list.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:54:21