我有TableView与海关单元代表事件。它看起来非常接近第一和第三张图像。
正如您在某些活动中所看到的(对不起小分辨率),会有朋友的照片参加。 不幸的是,关于朋友的信息没有加载有关事件的其他信息。
因此,在我获得事件列表后,我可以请求加载将参与每个事件的朋友列表。
现在我使用像
这样的代码class EventCell : UITableViewCell {
var eventForCell : Event? {
didSet {
eventTitleLabel.text = eventForCell.title
eventDateLabel.text = eventForCell.date
presentFriends(eventID : eventForCell.id)
}
}
func presentFriends(eventID : Int) {
//searching for friends for event with specific eventID
.......
.......
//for every friend found adding UIImageView in cell
for friend in friendsOnEvent {
let avatar = UIImageView(....)
self.addSubview(avatar)
}
}
}
此代码有效,但照片不能以流畅的方式呈现。此外,如果您快速滚动列表,它们会开始闪烁。如果用户滚动快速的事件列表,甚至可能没有必要加载它们。所以我有两个问题:
更新
我在UITableViewPrefetchingDataSource协议中找到了关于 tableView(_:prefetchRowsAt:)方法的信息,我应该在这种情况下使用它吗?也许有人有一些经验吗?
答案 0 :(得分:2)
1。(重新)在cellForRowAt
期间创建视图对象通常是一种不好的做法。从屏幕截图中我假设单个单元格上有多少个化身有限制 - 我建议在单元格初始化程序中创建所有UIImageView
个对象,然后在presentFriends
中将图像设置为它们,或隐藏未使用的(isHidden = true
)或将其alpha设置为0(当然,不要忘记取消隐藏使用的那些)。
2. 如果您正在使用SDWebImage加载图片,请实施prepareForReuse
并取消当前下载以在滚动期间获得一些性能提升,并防止未定义的行为(当您尝试设置另一个图像,而前一个图像尚未下载)。基于this question,this one和this one,我希望如下:
override func prepareForReuse() {
super.prepareForReuse()
self.imageView.sd_cancelCurrentImageLoad()
}
Or you can use [this gist][4] for an inspiration.
P.S。:此外,由于图像是从网上下载的,因此您将不得不指望一些闪烁 - 总会有一些延迟。通过缓存,您可以立即获得已下载的内容,但新内容会有延迟 - 无法阻止(除非您在呈现tableView之前预加载tableView中可能出现的所有图像)。
P.S.2:您可以尝试使用[UITableViewDataSourcePrefetching][6]
实现预取。这可以帮助您解决因从网上下载头像而导致的闪烁问题。这会让事情变得复杂一点,但是如果你真的想要消除这种眨眼,你将不得不弄脏你的手。
首先,正如您从文档中看到的那样,prefetchRowsAt
没有为您提供单元格对象 - 因此您必须将图像预取到模型对象,而不是简单地使用sd_setImage
给定单元格的UIImageView
对象。也许前面提到的gist可以帮助您将图像下载到模型中。
现在也是documentation州:
异步加载数据
不一定要为表视图中的每个单元调用
tableView(_:prefetchRowsAt:)
方法。因此,您tableView(_:cellForRowAt:)
的实施必须能够应对以下潜在情况:已通过预取请求加载数据,并准备好显示。
目前正在预取数据,但尚未提供。
尚未请求数据。
简单地说,当你在cellForRowAt
时,你不能依赖prefetchRowsAt
被调用 - 它可能已被调用,它可能没有被调用(或者可能正在调用)
文档继续建议使用Operation
作为下载资源的后备工具 - prefetchRowsAt
可以创建Operation
个对象,负责下载给定行的头像。然后cellForRowAt
可以向模型询问给定行的Operation
个对象 - 如果没有,则表示没有为该行调用prefetchRowsAt
,并且您必须创建{ {1}}此时的对象。否则,您可以使用Operation
创建的操作。
无论如何,如果您认为值得,可以使用此tutorial作为实现预取的灵感。
答案 1 :(得分:0)
如您所述,您可以使用UITableViewDataSourcePrefetching
。
这是一个协议,当某些单元格将要显示但尚未出现在屏幕上时,它会调用您的预取数据源。
通过这种方式,您可以准备在呈现之前需要花费时间加载的所有资源。
你必须实施:
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath])
并从所有indexpaths
获取与单元格相关的数据。
请注意它仅在 iOS10 之后才可用。
我个人使用带有缓存的AlamofireImage,因此已经下载的图像不会被提取两次,有很多替代方案,但在这种情况下使用缓存图像是一种很好的做法。