如何在通过完成处理程序接收到解析后的数据后在 table 视图中正确显示它们
How to properly display parsed data in table view after receiving them through completion handler
我需要在 tableView 中显示有关电影的信息(取自 https://developers.themoviedb.org/)。我正在使用单例进行网络请求,然后通过完成处理程序将解析后的数据传递给 tableViewController。我可以打印接收到的数据,但无法在 tableView 单元格中正确设置它们。你能帮我解决这个问题吗?
网络管理员
func getMovies(completion: @escaping ([Movies]?) -> Void) {
guard let url = URL(string: "https://api.themoviedb.org/3/movie/now_playing?api_key=\(apiKey)&language=en")
else { fatalError("Wrong URL") }
URLSession.shared.dataTask(with: url) { (data, response, error) in
if let jsonData = data {
let decoder = JSONDecoder()
do {
let moviesResult = try decoder.decode(MoviesResult.self, from: jsonData)
let movies = moviesResult.results
completion(movies)
}
catch {
print(error)
}
}
}.resume()
}
电影视图控制器
var movies = [Movies]()
override func viewDidLoad() {
super.viewDidLoad()
network.getMovies { result in
if let result = result {
self.movies = result
print(self.movies)
}
}
extension MoviesViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return movies.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let movie = movies[indexPath.row]
print(movie)
if let cell = tableView.dequeueReusableCell(withIdentifier: "moviesMainInfo", for: indexPath) as? MovieTableViewCell {
cell.filmTitle.text = movie.title
cell.filmRating.text = String(movie.popularity!)
return cell
}
return UITableViewCell()
}
}
解析结果: [MovieApp.Movies(genreIDs: Optional([14, 28, 12]), overview: Optional("Wonder Woman comes conflict with the 1980 年代寒冷时期的苏联 War,并发现了一个名为猎豹的强大敌人。”),受欢迎程度:可选(1927.057),标题:可选(“神奇女侠 1984”),发布日期:可选( "2020-12-16"), posterPath: Optional("/8UlWHLMpgZm9bx6QYh0NFoq67TZ.jpg")),
您做的一切都正确,您只需要在数据到达时重新加载 UITableView
。请注意,您需要在主线程上重新加载 UITableView
,因为 UIKit
不是线程安全的:
否则您的应用程序很可能会崩溃:
private func reloadTableView() {
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
另外,我鼓励您从 viewDidLoad
中提取您的网络功能。另一个改进是在闭包中使用 [weak self]
以避免内存泄漏:
private func loadData() {
network.getMovies { [weak self] result in
if let result = result {
self?.movies = result
print(self?.movies)
self?.reloadTableView()
} else {
// Maybe show some info that the data could not be fetched
}
}
}
然后在你的 viewDidLoad
中调用它:
override func viewDidLoad() {
super.viewDidLoad()
loadData()
}
我需要在 tableView 中显示有关电影的信息(取自 https://developers.themoviedb.org/)。我正在使用单例进行网络请求,然后通过完成处理程序将解析后的数据传递给 tableViewController。我可以打印接收到的数据,但无法在 tableView 单元格中正确设置它们。你能帮我解决这个问题吗?
网络管理员
func getMovies(completion: @escaping ([Movies]?) -> Void) {
guard let url = URL(string: "https://api.themoviedb.org/3/movie/now_playing?api_key=\(apiKey)&language=en")
else { fatalError("Wrong URL") }
URLSession.shared.dataTask(with: url) { (data, response, error) in
if let jsonData = data {
let decoder = JSONDecoder()
do {
let moviesResult = try decoder.decode(MoviesResult.self, from: jsonData)
let movies = moviesResult.results
completion(movies)
}
catch {
print(error)
}
}
}.resume()
}
电影视图控制器
var movies = [Movies]()
override func viewDidLoad() {
super.viewDidLoad()
network.getMovies { result in
if let result = result {
self.movies = result
print(self.movies)
}
}
extension MoviesViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return movies.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let movie = movies[indexPath.row]
print(movie)
if let cell = tableView.dequeueReusableCell(withIdentifier: "moviesMainInfo", for: indexPath) as? MovieTableViewCell {
cell.filmTitle.text = movie.title
cell.filmRating.text = String(movie.popularity!)
return cell
}
return UITableViewCell()
}
}
解析结果: [MovieApp.Movies(genreIDs: Optional([14, 28, 12]), overview: Optional("Wonder Woman comes conflict with the 1980 年代寒冷时期的苏联 War,并发现了一个名为猎豹的强大敌人。”),受欢迎程度:可选(1927.057),标题:可选(“神奇女侠 1984”),发布日期:可选( "2020-12-16"), posterPath: Optional("/8UlWHLMpgZm9bx6QYh0NFoq67TZ.jpg")),
您做的一切都正确,您只需要在数据到达时重新加载 UITableView
。请注意,您需要在主线程上重新加载 UITableView
,因为 UIKit
不是线程安全的:
否则您的应用程序很可能会崩溃:
private func reloadTableView() {
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
另外,我鼓励您从 viewDidLoad
中提取您的网络功能。另一个改进是在闭包中使用 [weak self]
以避免内存泄漏:
private func loadData() {
network.getMovies { [weak self] result in
if let result = result {
self?.movies = result
print(self?.movies)
self?.reloadTableView()
} else {
// Maybe show some info that the data could not be fetched
}
}
}
然后在你的 viewDidLoad
中调用它:
override func viewDidLoad() {
super.viewDidLoad()
loadData()
}