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

Foo*_*ook 14 uitableview uiimageview ios swift

我有一个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()
Run Code Online (Sandbox Code Playgroud)

UIImageView是故事板场景的出口.该UIImageView内容模式是看点飞度.

UIImageView可见细胞最初显示为空(无图像),即使我已确认的图像设置.直到单元格在屏幕上滚动,单元格才会重绘(?)并显示图像.

所以这似乎是某种时间问题,但我无法弄明白.在dispatch_async设置图像后,我尝试在块中调用以下所有内容:

self.pictureView.setNeedsDisplay()
self.pictureView.setNeedsUpdateConstraints()
self.pictureView.setNeedsLayout()
self.pictureView.reloadInputViews()
Run Code Online (Sandbox Code Playgroud)

这些都没有解决问题.是什么导致此图像仅在单元格滚出/进入视图后显示?

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

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

1)我的UIViewController包含一个UITableView.

2)这UITableView会从UITableViewCell名为PostCell 的自定义类中加载单元格.

3)PostCell的全部内容是从名为PostView(带有PostView类)的笔尖加载的单个视图.init:style:reuseIdentifier在PostCell 期间发生了这种负载:

postView = NSBundle.mainBundle().loadNibNamed("PostView", owner: self, options: nil).first as? PostView
Run Code Online (Sandbox Code Playgroud)

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

postView.post = Post
Run Code Online (Sandbox Code Playgroud)

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

5)postPostView上的属性有一个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

    }
Run Code Online (Sandbox Code Playgroud)

编辑4:

我发现,如果我UIImageView通过在笔尖中预先设置占位符图像来"填充",则将图像加载到该图像中UIImageView,图像将显示在占位符的高度.当我将该单元格从屏幕拉出然后再次打开时,UIImageView将使用笔尖中的约束设置以正确的大小绘制图像.

因此,似乎UIImageView已经在图像加载时设置了约束和大小,并且将其从屏幕上拉开/导致重新绘制某种类型以正确调整图像大小.如果我能以编程方式触发重绘它会有所帮助,但请参阅上面我已经尝试过的内容.

编辑6:

这是在行动.请注意,我在笔尖中设置了占位符图像.这似乎导致图像在最初加载时显示,但在占位符的维度上显示.在屏幕外滚动它会导致调整大小,然后正确显示. 在此输入图像描述

编辑7:

我在我的应用程序的其他地方使用PostView nib没有问题.加载时,图像大小正确.这个问题似乎只出现在nib内嵌了一个UITableViewCell.

编辑8:

我找到了这个问题的根本原因,在我的viewDidLoad中调用UIViewController:

tableView.estimatedRowHeight = 500
tableView.rowHeight = UITableViewAutomaticDimension
Run Code Online (Sandbox Code Playgroud)

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

0nd*_*re_ 4

你可以尝试这个扩展:

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()
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以把这条线放在你想要的任何地方

cell.cellPhoto.downloadedFrom(link: "customImageUrl", contentMode: .ScaleAspectFit) //Try changing contentMode
Run Code Online (Sandbox Code Playgroud)