Search code examples
iosswiftuitableviewasynchronousuiimageview

Repeating images when scrolling in UITableView Swift


EDITED CODE FROM BELOW ANSWER

WHAT I WANT

The images are correct size and show in the correct positions

The images are correct size and show in the correct positions

WHAT I GET

A bunch of images showing up everywhere randomly when I scroll

A bunch of images showing up everywhere randomly

I have looked through so many answers and I still haven't found a solution to my problem. It seems quite often it is a different problem for each person, and it doesn't help that most questions here are in Objective-C. I find it difficult converting from one to another.

I will just show my table view functions and explain my code and maybe somebody can identify the problem or help me to identify to solve it myself.

-----------------------------------------------------------------------------------

Explanation

Not all News Items (cells) contain pictures. So as you can see (in the first function below) I loop through the sections and the nested cells and if the news item contains a picture if newslists[i][j] != "None, I display the image. From this point it is familiar code, seen from the tutorial here

In the second function I once again loop through the sections and the cells till I land on one that should contain an image. I then change the height of this cell so the image will fit inside.

That is pretty much it... any ideas?

-----------------------------------------------------------------------------------

CellForRowAtIndexPath

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

    let cell = tableView.dequeueReusableCellWithIdentifier("NewsCell", forIndexPath: indexPath) as! UITableViewCell

    if newslists[indexPath.section][indexPath.row].imageURL != "None"{

        let urlString = newslists[indexPath.section][indexPath.row].imageURL

        let imgURL = NSURL(string: urlString)

        cell.imageView?.image = UIImage(named: "first")  // placeholder

        if let img = imageCache[urlString] {
            cell.imageView?.image = img
            println("loaded from cache")
        }
        else {

            let request: NSURLRequest = NSURLRequest(URL: imgURL!)
            let mainQueue = NSOperationQueue.mainQueue()
            NSURLConnection.sendAsynchronousRequest(request, queue: mainQueue, completionHandler: { (response, data, error) -> Void in
                if error == nil {

                    let image = UIImage(data: data)
                    self.imageCache[urlString] = image

                    dispatch_async(dispatch_get_main_queue(), {
                        if let cellToUpdate = tableView.cellForRowAtIndexPath(indexPath) {
                            cellToUpdate.imageView?.image = image
                            println("succesfully downloaded image")
                            println("size of cache is \(self.imageCache.count)")
                        }
                    })
                }
                else {
                    println("Error: \(error.localizedDescription)")
                }

            })
        }
    }


    cell.backgroundColor = UIColor(red: 52/255, green: 138/255, blue: 169/255, alpha: 1.0)

    return cell

}

I have one more function that may be causing problems but I doubt it:

HeightForRowAtIndexPath

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {

if newslists[indexPath.section][indexPath.row].imageURL != "None"{
    println("Expanding cell for \(indexPath.section)  \(indexPath.row)")
    return 190.0
}

    return 70.0
}

Solution

  • I'm not sure why you have a double for loop in both method. There are called for every indexPath possible so you can just get you appropriate data with the indexPath section and row.

    You can try this code, i don't see any reason for it to not work.

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    
        let cell = tableView.dequeueReusableCellWithIdentifier("NewsCell", forIndexPath: indexPath) as! UITableViewCell
        cell.imageView?.image = nil
    
        if newslists[indexPath.section][indexPath.row].imageURL != "None"{
    
            let urlString = newslists[indexPath.section][indexPath.row].imageURL
    
            let imgURL = NSURL(string: urlString)
    
            cell.imageView?.image = UIImage(named: "first")  // placeholder
    
            if let img = imageCache[urlString] {
                cell.imageView?.image = img
                println("loaded from cache")
            }
            else {
                ...
            }
        }
        return cell
    }
    
    
    
    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    
        if newslists[indexPath.section][indexPath.row].imageURL != "None"{
            println("Expanding cell for \(i)  \(j)")
            return 190.0
        }
    
        return 70.0
    }