0

My UITableViewCells images are displaying until I scroll back upwards whereby the images would not be displayed until the cell is selected.

The same problem also happens when I switch from another ViewController to the initial ViewController*(which contains the image)*

I have checked that the imgURL of the image is correct.

Libraries used are: AFNetworking for the image

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("FeedCell", forIndexPath: indexPath) as! MyCell
    cell.itemImageView.image = nil
    self.configureCell(cell, atIndexPath: indexPath)
    return cell
}

// AFNetworking download and display image
func uploadIMG(cell:MyCell,imgURL:NSURL,placeholderIMG:String,atIndexPath indexPath: NSIndexPath) {

    var imageRequest: NSURLRequest = NSURLRequest(URL: imgURL)
    cell.itemImageView!.setImageWithURLRequest(imageRequest, placeholderImage: UIImage(contentsOfFile: "logo.png"), success: { [weak cell] request,response,image in

        if (cell != nil) {
            cell!.itemImageView.image = image
        }}        
        , failure: nil)
}

// called from cellForRowAtIndexPath, retrieve img url to update image
func configureCell(cell: MyCell, atIndexPath indexPath: NSIndexPath) {
    let item = self.items[indexPath.row] as MWFeedItem
    var URLofImage: NSURL = NSURL(string: item.link)!
    var session = NSURLSession.sharedSession()
    let task = session.dataTaskWithURL(URLofImage, completionHandler: {(data,response, error) in
        let text = NSString(data: data, encoding: NSUTF8StringEncoding)
        var home = HTMLDocument(data: data, contentTypeHeader: text as! String)
        var div = home.nodesMatchingSelector("img")
        var urlString = div[1].firstNodeMatchingSelector("img")
        let urlData = (urlString as HTMLElement).firstNodeMatchingSelector("img")
        var urlFinal = urlData.attributes["src"]! as! String

        if urlFinal != "/images/system/bookmark-shorturl.png" {
            // call updateIMG function
            self.uploadIMG(cell, imgURL: NSURL(string: "http:www.animenewsnetwork.com" + urlFinal)!, placeholderIMG: "logo.png",atIndexPath: indexPath)
        }
    })

Image representation of the problem (Initial image working fine)

Initial Image (Working fine)

Second Image (I scrolled downwards and then scrolled upwards, Image not showing)

enter image description here

I select some cells and the images for those cells will then appear

enter image description here

Wraithseeker
  • 1,794
  • 1
  • 16
  • 33

4 Answers4

2

Try after setting image into cell, update that cell in table view by calling method tableView:reloadRowsAtIndexPaths:withRowAnimation. Or write your custom cell with custom image view. And please, do not forgot that image setting code must run in main thread.

Vasyl Khmil
  • 2,499
  • 1
  • 18
  • 33
  • I tried using that method and my images don't display or either appeared at the wrong location. I am using a subclass of UITableViewCell with my own custom image. – Wraithseeker May 04 '15 at 18:18
  • @vasyl That's a really neat way for recalculating the cell layout. – Tobias May 04 '15 at 18:20
  • 1
    @chiken Remember the TableView reuses cells. So the image property might be set from previous data. Adding `cell.itemImageView.image = nil` in `configureCell` should clear out the old image. – Tobias May 04 '15 at 18:21
  • @Tobias I tried setting it to nil but the image only appears after I select the cell still – Wraithseeker May 04 '15 at 18:29
  • @chiken Let me set up a test project and see if I can duplicate the issue. – Tobias May 04 '15 at 18:36
  • I also updated my main post with pictures if that will help to describe the problem better – Wraithseeker May 04 '15 at 18:47
  • @chiken Do you need to use [weak cell] in `session.dataTaskWithURL` completionHandler? I'm unable to duplicate the issue. I did notice that when I scroll down and scroll up that the image had to download again. – Tobias May 04 '15 at 19:12
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/76925/discussion-between-tobias-and-chiken). – Tobias May 04 '15 at 19:18
  • @VasylKhmil, bro could you help me to look at my question https://stackoverflow.com/questions/44541403/collection-view-inside-table-does-not-load-immediately-in-swift-3 ? – May Phyu Jun 19 '17 at 04:28
2

The problem was that my Image wasn't set on the main thread. To solve the problem, I simply used the following code below which ensured that my image will be set immediately.

dispatch_async(dispatch_get_main_queue(), {
 // do image functions here

)}
Wraithseeker
  • 1,794
  • 1
  • 16
  • 33
0

Misread the Question, but keeping this in case anyone has a similar problem, but with autolayout.

I believe you are using autolayout. So if the imageView's frame size is using the intrinsic content size, the size of it's image, it'll be CGSizeZero when there is no image. There is no image when the cell is first displayed, because it needs to be downloaded. So then the image is downloaded and gets assigned to imageView.image. This does not automatically invalidate the layout. You'll need to do that so the imageView frame gets recalculated based on the size of the image. The reason it shows up after scrolling away and scrolling back or selecting it is because the image has been downloaded in that time and the cells layout is recalculated when it gets displayed again or selected.

Below is my TestCell and TestViewController

import UIKit
import AFNetworking

class TestCell : UITableViewCell {
    static let cellIdentifier = "TestCell"

    @IBOutlet var downloadedImageView: UIImageView!
    @IBOutlet var rowLabel: UILabel!
    @IBOutlet var statusLabel: UILabel!

}


class TestTableViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        tableView.rowHeight = 100
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 30;
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCellWithIdentifier(TestCell.cellIdentifier, forIndexPath: indexPath) as! TestCell

        let randomName = "\(Random.firstName().lowercaseString).\(Random.lastName().lowercaseString)"
        let randomImageURL = NSURL(string: Random.avatarImageURL(name: randomName))!

        cell.rowLabel.text = String(indexPath.row)
        cell.statusLabel.text = "Not Downloaded"

        var imageRequest: NSURLRequest = NSURLRequest(URL: randomImageURL)
        cell.downloadedImageView.setImageWithURLRequest(imageRequest, placeholderImage: UIImage(named: "placeholder.png"),
            success: { [weak cell]
                (request, response, image) in
                if let cell = cell {
                    cell.downloadedImageView.image = image
                    cell.rowLabel.text = String(indexPath.row)
                    cell.statusLabel.text = "Downloaded"
                }
            },
            failure: { [weak cell]
                (request, response, error) in
                if let cell = cell {
                    cell.downloadedImageView.image = nil
                    cell.rowLabel.text = String(indexPath.row)
                    cell.statusLabel.text = "Failed: \(error.localizedDescription)"
                }
            })

        return cell

    }



}

//
//  Random.swift

import Foundation


class Random {


    static let firstNames = ["Tora", "Shasta", "Camelia", "Gertrudis", "Charita", "Donita", "Debbra", "Shaquana", "Tommy", "Shara", "Ignacia", "Cassondra", "Melynda", "Lisette", "Herman", "Rhoda", "Farah", "Tim", "Tonette", "Johnathon", "Debroah", "Britni", "Charolette", "Kyoko", "Eura", "Nevada", "Lasandra", "Alpha", "Mirella", "Kristel", "Yolande", "Nelle", "Kiley", "Liberty", "Jettie", "Zoe", "Isobel", "Sheryl", "Emerita", "Hildegarde", "Launa", "Tanesha", "Pearlie", "Julianna", "Toi", "Terina", "Collin", "Shamika", "Suzette", "Tad"]

    static let lastNames = ["Austen", "Kenton", "Blomker", "Demars", "Bibbs", "Eoff", "Alcantara", "Swade", "Klinefelter", "Riese", "Smades", "Fryson", "Altobelli", "Deleeuw", "Beckner", "Valone", "Tarbox", "Shumate", "Tabone", "Kellam", "Dibiase", "Fasick", "Curington", "Holbrook", "Sulzer", "Bearden", "Siren", "Kennedy", "Dulak", "Segers", "Roark", "Mauck", "Horsman", "Montreuil", "Leyva", "Veltz", "Roldan", "Denlinger", "James", "Oriley", "Cistrunk", "Rhodes", "Mcginness", "Gallop", "Constantine", "Niece", "Sabine", "Vegter", "Sarnicola", "Towler"]


    class func int(#min: Int, max: Int) -> Int {
        return Int(arc4random_uniform(UInt32(max-min))) + min //???: RTFM on arc4random, might be need (max+1)-min.
    }

    class func int(#range: Range<Int>) -> Int {
        return int(min: range.startIndex, max: range.endIndex)
    }

    class func selectElement<T>(#array: [T]) -> T {
        return array[int(range: 0..<array.count)]
    }


    class func firstName() -> String {
        return Random.selectElement(array: Random.firstNames)
    }

    class func lastName() -> String {
        return Random.selectElement(array: Random.lastNames)
    }

    class func avatarImageURL(var name: String? = nil) -> String {

        if name == nil {
            name = "(Random.firstName().lowercaseString).Random.lastName().lowercaseString"
        }

        let avatarImageSize = Random.int(min: 40, max: 285)
        return "http://api.adorable.io/avatars/\(avatarImageSize)/\(name!)@gmail.png"
    }


    class func imageURL() -> String {

        let imageWidth = Random.int(min:120, max:1080)
        let imageHeight = Random.int(min:120, max:1080)

        return "http://lorempixel.com/g/\(imageWidth)/\(imageHeight)/"
    }

}
Tobias
  • 4,387
  • 3
  • 24
  • 32
  • I'm quite new to this but I am using a custom UITableViewCell with a fixed frame implemented on the storyboard. My current understanding is that since I am using AspectFill for the images and a custom UIImageView, the image frame should not change? – Wraithseeker May 04 '15 at 18:26
  • @chiken Yeah. I think I misread your question when I first answered. I thought the images weren't showing up when the cell was first displayed. So I now think the problem is the reuse of tableview cells. Try the in `configureCell` to use `cell.itemImageView.image = nil` to clear out the old data. – Tobias May 04 '15 at 18:29
  • @chiken I saw a similar question to your problem. Someone suggested that you double check that when you set the image your on the main thread. – Tobias May 06 '15 at 01:50
  • Do you mind posting the code fix? So if I run into the problem I'll know what to do? – Tobias May 06 '15 at 16:31
  • Added it as an answer below which was the modification that I made. I put it before I fetch the IMG from the web by using AFNetworking. – Wraithseeker May 06 '15 at 16:53
0

When you scroll, cell will reload. (you reload to redownload your image) -> it's problem.

Solved: You create array for save image data after download.

And cell get image from this array, not redownload

Hope this helpful!

Binladenit Tran
  • 121
  • 1
  • 1
  • 7