如何让tableview重新加载正确的数据?

问题描述 投票:0回答:1

我正在尝试构建一个应用程序,使用有关加密货币的数据对 JSON 进行解码。获取数据后,我计算每种代币的每日周转率,并根据我将代币放入四分之一列表中的百分比。

如果我更改 viewModel 中的 selectedList 属性并运行应用程序,tableView 将加载适当的列表。但是当我在运行时更改 selectedList 的值时,什么也没有发生。 selectedList -> didSet 中的 print 语句的输出发生了变化,但重新加载 tableview 的视图中 didLoadCoins 方法内的 print 语句的输出与应用程序启动时保持不变。

我做错了什么?

视图控制器

class TVMainViewController: UIViewController, TVMainViewControllerViewButtonDelegate {
    
    private let mainView = TVMainViewControllerView()
    private let viewModel = TVMainViewControllerViewModel()
    
    
    
    //MARK: - Lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()
      
        navigationController?.isNavigationBarHidden = true
        mainView.delegate = self
        viewModel.delegate = mainView
        setupUI()
        
        
    }
    
    func didTapSelectRangeButton() {
        let destinationVC = TVSelectRangeViewController()
        destinationVC.modalPresentationStyle = .pageSheet
        destinationVC.sheetPresentationController?.detents = [.medium()]
        destinationVC.sheetPresentationController?.prefersGrabberVisible = true
        
        destinationVC.viewModel = viewModel
        
        present(destinationVC, animated: true)
    }
    
    //MARK: - UI Setup
    private func setupUI() {
        ...
    }

查看

protocol TVMainViewControllerViewButtonDelegate {
    func didTapSelectRangeButton()    
}


final class TVMainViewControllerView: UIView, TVMainViewControllerViewModelDelegate {
    
    //MARK: - Variables
    private var viewModel = TVMainViewControllerViewModel()
    var delegate: TVMainViewControllerViewButtonDelegate?
    
    //MARK: - Initializers
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        viewModel.delegate = self
        setupTableView()
        setupUI()
        Task {
            await viewModel.decodeData {
                self.viewModel.delegate?.didLoadCoins()
            }

        }
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    
    //MARK: - Functions
    private func setupTableView() {
        tableView.register(VTMainTableViewCell.self, forCellReuseIdentifier: Constants.mainTableViewCell)
        tableView.dataSource = viewModel
    }
    
    func didLoadCoins() {
        print(viewModel.selectedList)
        DispatchQueue.main.async {
            self.tableView.reloadData()
        }
    }
    
    @objc func selectRange() {
        delegate?.didTapSelectRangeButton()
    }
    
    //MARK: - UI Setup
    private func setupUI() {
       ...
    }
}

视图模型

import UIKit

/// Communicate with the View to notify it that the data are loaded
protocol TVMainViewControllerViewModelDelegate {
    func didLoadCoins()
}

class TVMainViewControllerViewModel: NSObject {
    
    //MARK: - Variables
    private let networkManager = NetworkManager()
    //    private let baseURL = "https://api.coinlore.net/api/tickers/?start=0&limit=10"
    
    private var coinList = [Cryptocurrency]()
    private var liquidityAbove30List = [CryptoLiquidityModel]()
    private var liquidityAbove20List = [CryptoLiquidityModel]()
    private var liquidityAbove10List = [CryptoLiquidityModel]()
    private var liquidityBelow10List = [CryptoLiquidityModel]()
    private var coinLiquidityList = [CryptoLiquidityModel]()
    var delegate: TVMainViewControllerViewModelDelegate?
    
    var selectedList: Int = 0  {
        didSet {
            print(selectedList)
            delegate?.didLoadCoins()
        }
    }
    
    
    //MARK: - Functions
    
    /// Run networking task and fetch data. It makes 5 network call each of which fetches 100 coins
    func decodeData(completion: @escaping () -> Void) async {
        coinList = []
        var page = 0
        
        while page < 200 {
            let baseURL = "https://api.coinlore.net/api/tickers/?start=\(page)&limit=100"
            
            networkManager.execute(url: baseURL) { result in
                switch result {
                case.success(let decodedData):
                    for coin in decodedData.data {
                        self.coinList.append(coin)
                        self.calculateDailyTurnoverRatio(coin: coin)
                        
                        self.delegate?.didLoadCoins()
                    }
                case .failure(let error):
                    print(error)
                }
            }
            page += 100
            
        } //endwhile
        
        completion()
    }
    
    
    /// Calculate liquidity by dividing daily volume/market cap
    /// Creates 4 lists. Each list contains the coins that have the given turnover ration
    func calculateDailyTurnoverRatio(coin: Cryptocurrency) {
        coinLiquidityList = []
        
        
        let coinLiquidity24 = (coin.volume24 / Double(coin.market_cap_usd)!)*100
        let newCoin = CryptoLiquidityModel(cryptocurrency: coin, liquidity24: coinLiquidity24)
        
        switch coinLiquidity24 {
        case 30 ... 100:
            liquidityAbove30List.append(newCoin)
        case 20 ... 29:
            liquidityAbove20List.append(newCoin)
        case 10 ... 19:
            liquidityAbove10List.append(newCoin)
        default:
            liquidityBelow10List.append(newCoin)
        }
        
    }
    
    
}


extension TVMainViewControllerViewModel: UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        switch selectedList {
        case 0:
            return liquidityBelow10List.count
        case 1:
            return liquidityAbove10List.count
        case 2:
            return liquidityAbove20List.count
        case 3:
            return liquidityAbove30List.count
        default:
            return liquidityBelow10List.count        }    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: Constants.mainTableViewCell, for: indexPath) as! VTMainTableViewCell
        
        switch selectedList {
        case 0:
            let coin = liquidityBelow10List[indexPath.row]
            cell.set(coinSymbol: coin.cryptocurrency.name,
                     coinPrice: coin.cryptocurrency.price_usd,
                     change24: coin.cryptocurrency.percent_change_24h,
                     liquidity24: String(format: "%.2f", coin.liquidity24))
        case 1:
            let coin = liquidityAbove10List[indexPath.row]
            cell.set(coinSymbol: coin.cryptocurrency.name,
                     coinPrice: coin.cryptocurrency.price_usd,
                     change24: coin.cryptocurrency.percent_change_24h,
                     liquidity24: String(format: "%.2f", coin.liquidity24))
            
        case 2:
            let coin = liquidityAbove20List[indexPath.row]
            cell.set(coinSymbol: coin.cryptocurrency.name,
                     coinPrice: coin.cryptocurrency.price_usd,
                     change24: coin.cryptocurrency.percent_change_24h,
                     liquidity24: String(format: "%.2f", coin.liquidity24))
            
        case 3:
            let coin = liquidityAbove30List[indexPath.row]
            cell.set(coinSymbol: coin.cryptocurrency.name,
                     coinPrice: coin.cryptocurrency.price_usd,
                     change24: coin.cryptocurrency.percent_change_24h,
                     liquidity24: String(format: "%.2f", coin.liquidity24))
            
        default:
            let coin = liquidityBelow10List[indexPath.row]
            cell.set(coinSymbol: coin.cryptocurrency.name,
                     coinPrice: coin.cryptocurrency.price_usd,
                     change24: coin.cryptocurrency.percent_change_24h,
                     liquidity24: String(format: "%.2f", coin.liquidity24))
            
        }
        
        return cell
        
    }    
}
swift uitableview uikit
1个回答
0
投票

您正在使用两个不同的

TVMainViewControllerViewModel
实例。如果不是有意的,我想这可能是导致此问题的原因之一。您可能认为视图和视图控制器正在与同一个视图模型实例进行通信,但事实并非如此(因为有两个)。

final class TVMainViewControllerView: UIView, TVMainViewControllerViewModelDelegate {
    
    //MARK: - Variables
    private let viewModel: TVMainViewControllerViewModel
    var delegate: TVMainViewControllerViewButtonDelegate?
    
    //MARK: - Initializers
    init(vm: TVMainViewControllerViewModel) {
      super.init(frame: .zero)
      self.viewModel = vm //Allocate view model from initializer.
      self.viewModel.delegate = self
      setupTableView()
      setupUI()
      Task {
            await viewModel.decodeData {
                self.viewModel.delegate?.didLoadCoins()
            }
      }
    }
   

class TVMainViewController: UIViewController, TVMainViewControllerViewButtonDelegate {
    
    private let viewModel = TVMainViewControllerViewModel()
    private lazy var mainView = TVMainViewControllerView(vm: self.viewModel)
    
    
    //MARK: - Lifecycle
    override func viewDidLoad() {
        super.viewDidLoad()
      
        navigationController?.isNavigationBarHidden = true
        mainView.delegate = self
       // viewModel.delegate = mainView // This one is not needed.
        setupUI()
        
        
    }

我只是简单修改了您的代码,以向您展示我仅使用一个

TVMainViewControllerViewModel 
实例的含义。请看一下什么是依赖注入,希望这能给您一些线索。

© www.soinside.com 2019 - 2024. All rights reserved.