首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在UITableViewCell中执行耗时的任务,暂停滚动

在UITableViewCell中执行耗时的任务,暂停滚动
EN

Stack Overflow用户
提问于 2018-03-18 10:32:35
回答 2查看 535关注 0票数 2

我有代表事件的海关单元格的TableView。它看起来非常接近这里的第一和第三张图像。

正如你所看到的(对于小解析度很抱歉),在一些活动中,有一些朋友的照片将要参加。不幸的是,关于朋友的信息并没有加载其他有关事件的信息。

因此,在我得到事件列表之后,我可以请求加载将要参加每个活动的朋友列表。

现在,我使用的代码如下

代码语言:javascript
复制
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)
        }
   }
}

此代码工作,但照片并不是以平滑的方式呈现。另外,如果你滚动列表快,他们开始眨眼。如果用户滚动快速事件列表,甚至没有必要加载它们。所以我有两个问题:

  1. 我如何使滚动顺利的经验,考虑到介绍朋友为每一个事件可能需要时间,有时它完成后,细胞滚动离开。
  2. 如果我已经加载了事件列表,并且已经显示了它们的单元格。在我得到关于将要参与的朋友的信息后,我如何更新这些细胞呢?
  3. 当用户正在滚动,而我正在创建异步任务以在单元格中显示一些图像时,我认为我应该使用对self的弱引用,并可能检查它不等于零,这样如果现在看不到单元格,任务就会被取消。应该怎么做呢?

更新:

我在tableView(_:prefetchRowsAt:)协议中找到了有关UITableViewPrefetchingDataSource方法的信息,我应该在这个例子中使用它吗?也许有人在这方面有经验?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-03-23 09:49:14

1. (Re)在cellForRowAt期间创建视图对象通常是一种糟糕的做法。从屏幕截图中,我假设一个单元格上有多少个化身是有限度的--我建议在单元格初始化器中创建所有的UIImageView对象,然后在presentFriends中将图像设置给它们,或者隐藏未使用的图像(isHidden = true),或者将它们的alpha设置为0(当然,不要忘记隐藏正在使用的图像)。

2.如果您正在使用SDWebImage加载映像、实现prepareForReuse和取消当前下载以在滚动期间获得一些性能提升,并防止未定义的行为(当您试图设置另一个映像,而之前的映像尚未下载时)。基于这个问题这一个这一个,我希望这样的事情:

代码语言:javascript
复制
    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不会给您一个单元对象--因此您必须将图像预取到您的模型对象,而不是简单地在给定单元格上对UIImageView对象使用sd_setImage。也许前面提到的要旨会帮助你下载图片来建模。

现在,正如文档声明的那样:

异步加载数据 对于表视图中的每个单元格,不一定要调用tableView(_:prefetchRowsAt:)方法。因此,tableView(_:cellForRowAt:)的实现必须能够处理以下潜在情况: 数据已通过预取请求加载,并已准备好显示。 数据目前正在预取,但尚未可用。 尚未要求提供数据。

简单地说,当您在cellForRowAt中时,您不能依赖调用prefetchRowsAt --它可能已经被调用,也可能没有被调用(或者调用正在进行中)。

文档继续建议使用Operation作为下载资源的支持工具-- prefetchRowsAt可以创建负责为给定行下载化身的Operation对象。然后,cellForRowAt可以询问给定行的Operation对象的模型--如果没有,这意味着没有为该行调用prefetchRowsAt,因此必须在此时创建Operation对象。否则,您可以使用prefetchRowsAt创建的操作。

无论如何,如果您认为这是值得的,您可以使用这个教程作为实现预取的灵感。

票数 2
EN

Stack Overflow用户

发布于 2018-03-23 09:52:22

您可以像前面提到的那样使用UITableViewDataSourcePrefetching

这是一种协议,当要显示一些单元时调用预取数据源,但尚未显示在屏幕上。

通过这种方式,您可以准备所有需要时间加载的资源,然后才会显示它们。

你只需要实现:

代码语言:javascript
复制
func tableView(_ tableView: UITableView, prefetchRowsAt indexPaths: [IndexPath])

并从所有indexpaths中获取与单元格相关的数据。

请注意,它只在iOS10之后才可用。

我个人在缓存中使用AlamofireImage,这样已经下载的图像不会被抓取两次,有很多替代方法,但是在这种情况下使用缓存的映像是一个很好的实践。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49346881

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档