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



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")
}
}

一旦所有数据都完成加载,就需要重新加载表视图。现在,当这些网络操作仍在运行时,您的代码将重新加载表视图。

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

您可以使用DispatchGroup来帮助您。

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

您在处理weak self时也有一些错误——如果self不是nil,您的代码就会返回。你想要的恰恰相反。

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?)的闭包,而不是使用两个闭包。

Edit:我在建议将async更改为sync时犯了一个错误。正如@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()
}

}

我希望我能帮上一点忙。如果你有什么需要澄清的,我很乐意帮忙。

最新更新