ios - UIImageView 最初不会在 UITableViewCell 中显示图像

标签 ios swift uitableview uiimageview

我有一个 UITableView从服务加载图像。它获取 URL 并使用 NSURLSession.sharedSession().dataTaskWithURL 下载图像:

NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: { (data, _, error) -> Void in
                            guard
                                let data = data where error == nil,
                                let image = UIImage(data: data)
                                else {
                                    print(error?.localizedDescription)
                                    return
                            }
                            dispatch_async(dispatch_get_main_queue()) {
                                [unowned self] in
                                self.pictureView.image = image
                                self.pictureView.layoutIfNeeded()
                            }
                        }).resume()
UIImageView是 Storyboard场景的导出。 UIImageView内容模式是 Aspect Fit。
UIImageView即使我已确认设置了图像,可见单元格最初显示为空(无图像)。直到单元格在屏幕上滚动关闭/滚动,单元格才会重绘(?)并显示图像。

所以这似乎是某种时间问题,但我无法弄清楚。我尝试在 dispatch_async 中调用以下所有内容设置图像后的 block :
self.pictureView.setNeedsDisplay()
self.pictureView.setNeedsUpdateConstraints()
self.pictureView.setNeedsLayout()
self.pictureView.reloadInputViews()

这些都不能解决问题。是什么导致此图像仅在单元格滚动出/进入 View 后显示?

编辑:
值得注意的是,这是发生在 nib 和相关类中的。 Nib 已加载,然后我开始下载。我想知道 Nib 是否会自行布置,当我的图像被下载并设置在 UIImageView 上时布局通行证已完成。然后通过在屏幕上移动单元格(包含 Nib ),单元格再次执行布局并正确显示所有内容。只是一个猜测,我仍然坚持这一点。

编辑2:
进一步澄清过程:

1) 我的UIViewController包含 UITableView .

2) 这个UITableView从自定义 UITableViewCell 加载单元格名为 PostCell 的类。

3) PostCell 的全部内容是从名为 PostView 的 nib 加载的单个 View (带有 PostView 类)。该负载发生在 init:style:reuseIdentifier 期间。在 PostCell 中:
postView = NSBundle.mainBundle().loadNibNamed("PostView", owner: self, options: nil).first as? PostView

4) 然后我在 postView 上设置一个 Post 对象:
postView.post = Post

请注意,这发生在 awakeFromNib() 之后。在 PostView 上调用。

5) post PostView 上的属性有 didSet观察者根据 post 中的 URL 启动图像下载对象(上面的代码)。图像已下载并设置在 UIImageView命名为 pictureView .

编辑3:

这是 tableView(_:cellForRowAtIndexPath:) 的代码:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    var cell = tableView.dequeueReusableCellWithIdentifier(postCellIdentifier) as? PostCell

        if cell == nil {
           cell = PostCell()
        }

        if let postCell = cell,
            let postArray = postArray,
            let post = postArray[indexPath.row] {
            postCell.post = post
            return postCell
        }

        // This section is hit during a refresh.
        let emptyCell = UITableViewCell()
        emptyCell.contentView.backgroundColor = .whiteColor()
        return emptyCell

    }

编辑4:

我发现如果我“启动”UIImageView通过在 Nib 中预先设置占位符图像,然后将我的图像加载到 UIImageView ,图像将显示在占位符的高度。当我将该单元格拉出屏幕然后再次打开时,UIImageView将使用 Nib 中的约束设置以正确的大小绘制图像。

所以看来 UIImageView 的约束和大小已在图像加载时设置,并且将其从屏幕上拉下/拉上会导致某种重绘以正确调整图像大小。如果我可以以编程方式触发重绘,它会有所帮助,但请参阅上面我已经尝试过的内容。

编辑6:

这是在行动。请注意,我在 Nib 中设置了一个占位符图像。这似乎导致图像在最初加载时显示,但在占位符的尺寸上。当它正确显示时,将其短暂滚动到屏幕外会导致调整大小。
enter image description here

编辑 7:

我在我的应用程序的其他地方使用 PostView nib 没有问题。当它加载图像大小正确。问题似乎只出现在 Nib 嵌入 UITableViewCell 中。 .

编辑 8:

我找到了这个问题的根本原因,在我的 UIViewController 的 viewDidLoad 中调用。 :
tableView.estimatedRowHeight = 500
tableView.rowHeight = UITableViewAutomaticDimension

使用自动尺寸会导致初始不正确的行高。出于某种原因,将单元格滚动出/进入 View 将正确重新计算行高,并且图像以正确的高度显示。删除此代码将显示图像,但行高不会从自动高度计算中受益。自动计算行高并且仍然避免这个问题的最佳方法是什么?

最佳答案

你可以试试这个扩展:

extension UIImageView {
    func downloadedFrom(link link:String, contentMode mode: UIViewContentMode) {
        guard
            let url = NSURL(string: link)
            else {return}
        contentMode = mode
        NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: { (data, response, error) -> Void in
            guard
                let httpURLResponse = response as? NSHTTPURLResponse where httpURLResponse.statusCode == 200,
                let mimeType = response?.MIMEType where mimeType.hasPrefix("image"),
                let data = data where error == nil,
                let image = UIImage(data: data)
                else { return }
            dispatch_async(dispatch_get_main_queue()) { () -> Void in
                self.image = image
            }
        }).resume()
    }
}

然后你可以把这条线放在你想要的任何地方
cell.cellPhoto.downloadedFrom(link: "customImageUrl", contentMode: .ScaleAspectFit) //Try changing contentMode

关于ios - UIImageView 最初不会在 UITableViewCell 中显示图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38058804/

相关文章:

ios - 不可见@interface声明选择器 'deleteAllObjects'

ios - Quickblox API 因无法识别的选择器而快速崩溃

iOS - 自定义表格单元格不是 UITableView 的全宽

iphone - TableViewCells 和字典数组

ios - Xcode Storyboard - 如何在不同的 iPhone 屏幕尺寸之间更改元素的字体大小和位置

ios - 如何将 -ObjC 添加到 Xcode 中的链接器文件

iOS:强制取消 NSOperationQueue 中的操作

ios - 使用多个自定义 UITableViewCells

ios - Swift 中的 Objective C Setter 覆盖

带有下一页预览的 Swift CollectionView slider