已加载UIImage,并且滚动经过1个单元格后,它会滞后并继续用于其他人。
extension TableViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return post.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: "myCell")
DispatchQueue.main.async {
//MARK:- UIImage as URL
let postImage = self.post[indexPath.row]
if let photoUrl = URL(string: postImage.photoUrl!)
{
do {
let data = try Data(contentsOf: photoUrl)
cell.imageView?.image = UIImage (data: data)
cell.imageView?.frame = CGRect(x: 0, y: 0, width: 450, height: 450)
} catch {
print("")
}
}// postImage
}
return cell
}
} //MARK:- Extension into Table View Controller
答案 0 :(得分:0)
它滞后是因为您在主线程上执行“大量”操作。 DispatchQueue.main.async在这里没有帮助,因为它仍在主线程中执行代码。您实际上只需要在主线程上执行以下两行代码:
cell.imageView?.image = UIImage (data: data)
cell.imageView?.frame = CGRect(x: 0, y: 0, width: 450, height: 450)
实际上,您甚至不需要第二个,因为布局应由单元格本身完成(例如,可以通过约束或自动调整大小的蒙版进行设置)
您的代码中最重的操作是let data = try Data(contentsOf: photoUrl)
,因为它从网络执行数据加载。因此,您的主要目标是在主线程之外执行此操作。例如,您可以这样做:
DispatchQueue.global().async {
do {
let data = try Data(contentsOf: photoUrl)
let image = UIImage(data: data) // this also could be pretty much heavy if the image is big so since we're already in background let's do it here
DispatchQueue.main.async {
imageView.image = UIImage (data: data)
}
}
catch {
print("")
}
}
该示例非常基本,仍然存在未解决的问题。例如,如果将图像设置为imageView时要比缩放图像大很多,那也可能会很昂贵,因此最好在后台线程中将图像缩放为imageView大小。此外,单元格是可重用的,因此当加载一个图像时,该单元格可能已用于显示另一幅图像,因此您还需要一种处理它的方法。另外,您可能需要缓存加载的图像,以避免每次滚动时从网络上重新加载它们。
因此,这里有很多工作要做,为了简化起见,我建议您使用Kingfisher之类的库(仅作为示例,不要广告)