如何在 TableView 重新加载之前设置模型数据

How Set Model Data Before TableView Reload

TableView 在设置模型数据 (topRatedModel) 之前重新加载,因此模型保持为零。我用了主胎面,但没有用。我怎样才能解决这个问题 ?您可以查看我的代码:https://github.com/melisaozturk/MVVM (主分支是最新的)

    class MovieViewController: UIViewController {

    @IBOutlet weak var tableView: UITableView!
    let viewModel = MovieViewModel()
    var topRatedModel: MovieTopRatedModel!
    var nowPlayingModel: MovieNowPlayingModel!
    var popularModel: MoviePopularModel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.tableRegister()
        self.viewModel.getTopRatedData(completion: { [weak self] response in
            if let _ = self {return}
            self!.topRatedModel = response
        }, completionHandler: { [weak self] error in
             if let _ = self {return}
        })
        
        
        self.viewModel.getNowPlayingData(completion: { [weak self] response in
            if let _ = self {return}
            self!.nowPlayingModel = response
        }, completionHandler: { [weak self] error in
            if let _ = self {return}
        })
        
        self.viewModel.getPopularData(completion: { [weak self] response in
            if let _ = self {return}
            self!.popularModel = response
        }, completionHandler: { [weak self] error in
            if let _ = self {return}
        })
        
        DispatchQueue.main.async {
            self.tableView.reloadData()
        }
       
    }

     private func tableRegister() {
        self.tableView.delegate = self
        self.tableView.dataSource = self
        self.tableView.separatorStyle = .none
        self.tableView.tableFooterView = UIView()
        self.tableView.separatorStyle = .none
        
        self.tableView.register(UINib(nibName: "MovieCell", bundle: nil), forCellReuseIdentifier: "MovieCell")
    }
}

编辑:我犯了一个错误,建议将异步更改为同步。这是错误的,因为它可能导致主线程被阻塞,正如@Paulw11 指出的那样。

我能想到的解决方案是使用 DispatchGroups 或调度信号量。我个人更喜欢 DispatchGroups,所以我会给你一些关于如何实现它的伪代码:

override func viewDidLoad() {
    super.viewDidLoad()
    
    self.tableRegister()

    let dispatcher = DispatchGroup()

    //for every function that you want to wait for you make an dispatcher.enter()
    dispatcher.enter()
    self.viewModel.getTopRatedData(completion: { [weak self] response in
        if let _ = self {return}
        self!.topRatedModel = response
    }, completionHandler: { [weak self] error in
         if let _ = self {
             // when each of the functions has finished running you can write a dispatcher.leave()
             dispatcher.leave()
             return
         }
    })
    
    // This code will wait for all dispatcher.leaves() to run in order to execute the following code.
    dispatcher.notify(.main){
        self.tableView.reloadData()
    }
   
}

希望我能帮上一点忙。如果您需要更多说明,我很乐意提供帮助。

所有数据加载完成后,您需要重新加载 table 视图。您的代码现在重新加载 table 视图,而这些网络操作仍然是 运行.

现在,您有三个网络操作,您不想在它们全部完成之前重新加载,并且您不知道它们将按什么顺序完成。

您可以在这里使用 DispatchGroup 来帮助您。

DispatchGroup 上使用 notify 你可以在调度组变空时执行一些代码。

您在处理 weak self 时也有一些错误 - 如果 self 不为零,您的代码将 return。你想要的恰恰相反。

override func viewDidLoad() {
        super.viewDidLoad()
        
        self.tableRegister()

        let dispatchGroup = DispatchGroup()
        

        dispatchGroup.enter()
        self.viewModel.getTopRatedData(completion: { [weak self] response in
            if let self = self else {
                self.topRatedModel = response               
            }
            dispatchGroup.leave()
        }, completionHandler: { [weak self] error in
             dispatchGroup.leave()
        })
        
        dispatchGroup.enter()
        self.viewModel.getNowPlayingData(completion: { [weak self] response in
            if let self = self {
                self.nowPlayingModel = response
            }
            dispatchGroup.leave()
        }, completionHandler: { [weak self] error in
            dispatchGroup.leave()
        })
        
        self.viewModel.getPopularData(completion: { [weak self] response in
            if let self = self {
                self.popularModel = response
            }
            dispatchGroup.leave()
        }, completionHandler: { [weak self] error in
            dispatchGroup.leave()
        })
        
        dispatchGroup.notify {
            DispatchQueue.main.async {
                self.tableView.reloadData()
            }
        }
       
    }

从风格的角度来看,我会使用 Result 类型或至少一个接受 (Response?,Error?) 的闭包,而不是使用两个闭包。