【问题标题】:not able to load data with ViewModel无法使用 ViewModel 加载数据
【发布时间】:2018-11-07 11:40:59
【问题描述】:
  • 在 IB 中正确设置了 tableView 数据源
  • 在 IB 中也正确设置了 viewController 身份

这是我的 viewModel

class StatusCodeViewModel {

    let apiClient = APIClient.shared
    var statusCodes: [StatusCode] = []
    let identifier = "statusCodeCell"

    init() {}


    func loadStatusCodes() {
        apiClient.execute(service: .statusCode) { statusCodes in
            self.statusCodes = statusCodes
        }
    }

}

以及我要在其中加载数据的 viewController

class ViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!
    var viewModel: StatusCodeViewModel? {
        didSet {
            if viewModel!.statusCodes.count > 0 {
                self.tableView.reloadData()
            }
        }
    }


    override func viewDidLoad() {
        super.viewDidLoad()
        viewModel = StatusCodeViewModel()
        viewModel!.loadStatusCodes()
    }
}

extension ViewController : UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if let statusCodes = viewModel!.statusCodes as? [StatusCode] {
            return statusCodes.count
        }
        return 0
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: viewModel!.identifier)
        cell?.textLabel!.text = viewModel!.statusCodes[indexPath.row].title
        return cell!
    }


}

数据计数为0,tableView中没有数据显示

【问题讨论】:

  • 从 API 加载数据后,您永远不会重新加载表。

标签: swift mvvm tableview viewmodel


【解决方案1】:

//这样就可以了!

     func loadStatusCodes(completion: @escaping () -> Void) {
               apiClient.execute(service: .statusCode) { statusCodes in
                   self.statusCodes = statusCodes
                   completion()
               }
           }
           

// 在 ViewController 中:

               override func viewDidLoad() {
                       super.viewDidLoad()
                       viewModel = StatusCodeViewModel()
                       viewModel?.loadStatusCodes() {
                           self.tableView.reloadData()
                       }
                   }

【讨论】:

    【解决方案2】:

    您已经在视图模型上进行了设置,这将在初始化时发生。

    当 api 返回调用时,您必须实现某种回调 - 最简单的方法是协议。

    protocol StatusCodeViewModelDelegate {
        func callFinished()
    }
    
    class StatusCodeViewModel {
    
        let apiClient = APIClient.shared
        var statusCodes: [StatusCode] = []
        let identifier = "statusCodeCell"
        var delegate : StatusCodeViewModelDelegate?
    
        init() {}
    
    
        func loadStatusCodes() {
            apiClient.execute(service: .statusCode) { statusCodes in
                self.statusCodes = statusCodes
                delegate?.callFinished()
            }
        }
    
    }
    

    然后在你的 viewController 中:

    override func viewDidLoad() {
        super.viewDidLoad()
        viewModel = StatusCodeViewModel()
        viewModel.delegate = self
        viewModel!.loadStatusCodes()
    }
    
    func callFinished() {
        self.tableView.reloadData()
    }
    

    不要忘记为您刚刚创建的委托进行扩展:

    class ViewController: UIViewController, StatusCodeViewModelDelegate {
    

    或者,正如@rmaddy 建议的那样,在查看模型中将loadStatusCodes 更改为:

    func loadStatusCodes(completion: @escaping () -> Void) {
        apiClient.execute(service: .statusCode) { statusCodes in
            self.statusCodes = statusCodes
        }
    }
    

    然后,在viewDidLoad中:

    override func viewDidLoad() {
        super.viewDidLoad()
        viewModel = StatusCodeViewModel()
        viewModel!.loadStatusCodes {
            self.tableView.reloadData()
        }
    }
    

    【讨论】:

    • loadStatusCodes 函数上完成关闭也是一个典型的解决方案。
    • 同意,代码会更少,但我更喜欢这种方式,因为您也可以将其提取到扩展中。感谢您的建议:)
    猜你喜欢
    • 2021-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多