异步下载后,在可见的UITableviewCell中设置图像

时间:2015-10-24 10:30:11

标签: ios swift uitableview alamofire

我有一个带有动态单元格的tableView。每个单元格都有一个imageView和一个textLabel。我正在和Alamofire&顺便说一下AlamofireImage。 我的问题是,第一个单元格(如果视图确实出现,您会看到)不会显示图像。但如果我向下滚动,我会看到其他细胞的图像。如果再次向上滚动,第一个单元格的图像也会出现。

  1. 首先,我在viewDidLoad方法中下载用户数据。完成此操作后,我使用tableView.reloadData()更新tableview。

    override func viewDidLoad() {
        super.viewDidLoad()
        MYRequest_getUsers(//...
            ,
            success: {response -> Void in
                self.users = response
                dispatch_async(dispatch_get_main_queue(),{
                    self.tableView.reloadData()
                })
            },
            failure: {NSError -> Void in
            debugPrint(NSError)
        })
    }
    
  2. TableView统计用户并重新加载。

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return users?.count ?? 0
    }
    
  3. 在tableView_cellForRowAtIndexPath方法中,我使用用户数据填充单元格。

    let cell = tableView.dequeueReusableCellWithIdentifier(self.identifier) as! UserCell
    
    cell.userNameLabel.tag = indexPath.row
    
    let rowData: User = self.users?[cell.userNameLabel.tag] as User!
    
    cell.userNameLabel.text = rowData.getName()
    
    let avatarURL = rowData.getAvatarURL() ?? ""
    
    cell.userImageView.af_setImageWithURL(imgURL, placeholderImage: placeholderImage)
    
    return cell
    
  4. 我的想法是,在加载用户数据后,tableView开始绘制自己并放置名称(因为它已经在userData中)。但是图像是异步下载的(我猜),所以它们在延迟一段时间之后来自后端,并且已经绘制了tableView。上下滚动后,我看到了它们。

    我想打开屏幕而不上下滚动。 Tableview应在加载后自动设置图像。所以我想做一个回调并使用而不是

        cell.userImageView.af_setImageWithURL(imgURL, placeholderImage: placeholderImage)
    

        Alamofire.request(.GET, avatarURL)
            .responseImage { response in
                cell.userImageView.image = response.2.value
                dispatch_async(dispatch_get_main_queue(), { () -> Void in
                    tableView.setNeedsLayout()
                })
        }
    

    但是没有任何改变......我已经尝试了很多并且看起来类似的问题但是无法解决它...我希望你能给我一些提示或更好的解决方案! :)

    提前致谢

3 个答案:

答案 0 :(得分:5)

我想通过发布步骤(在这种情况下遵循的最佳做法)给你一个方向:

第1步:只要您有来自服务器的图片网址,就可以在后台获取图片。我更喜欢在操作队列中这样做,我同时下载多个图像。您可以编写一个辅助类,它使用完成块并实现NSOperation / NSOperationQueue

第2步:在下载图片时,为了用户的眼睛,在图片视图上加载加载图层。您可以在cellForRowAtIndexPath:

中执行此操作

第3步:图像可用后,将它们缓存在文件系统中。这是为了避免任何滚动突然行为。

第4步:图像可用后,请调用完成块。

步骤5:在完成块中,在主线程上重新加载表。确保您的cellForRowAtIndexPath:首先检查缓存中的图像(如果有),如果不存在则显示加载覆盖,如果图像提取正在进行中。如果图像在缓存中不可用且下载也未进行,则显示一些默认图像。

答案 1 :(得分:2)

这个问题已有几年历史了,但也许这个答案对于有类似问题的其他人有用,就像我之前找到正确的解决方案一样。

由于图像是异步加载的,如果我们没有为UIIMageView提供固定的高度,我们必须在下载完成时强制更新单元格。这是因为单元更新(即AutoLayout约束重新计算)仅在initialParts()方法之后自动完成,该方法在第一次显示单元格时调用,或者在滚动表格以显示其他单元格时。在这两种情况下,cellForRowAt方法可能尚未下载图像,因此只显示占位符,因为它们的尺寸目前尚不清楚。

要强制更新单元格,我们需要使用af_setImage()beginUpdates()方法,将它们放在endUpdates()的完成处理程序中。这样,每次下载完成后,单元格都会更新。

但是,为了避免循环,在调用.af_setImage() / beginUpdates()之前,我们必须检查我们之前是否已经更新了单元格,因为通过调用这些方法,endUpdates()方法再次调用,因此cellForRowAt及其完成闭包,其中包含af_setImage() / beginUpdates()

这意味着我们必须仅在下载完成时更新单元格,而不是在成像被兑现时更新单元格(因为,如果它被兑现,则意味着我们已经更新了单元格)。这可以通过检查完成处理程序的响应来完成:如果它不是nil,则图像刚刚下拉,如果它是nil,则图像被兑现。

作为附带好处,细胞高度将自动调整(记得在endUpdates()方法中放置tableView.estimatedRowHeight = 400tableView.rowHeight = UITableViewAutomaticDimension

最后,这是代码:

viewDidLoad()

那是所有人! ; - )

答案 2 :(得分:0)

实现这一目标很少。

  • 在viewwillappear中调用数据下载,而不是在viewdidload中调用。
    • 在viewdidload中,隐藏tableview。
    • 在viewdidAppear中:检查数据是否已下载,如果是,则调用 [tableview reloaddata]方法。